From ef12f355998ae929142afd164c524792c6a86d36 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 26 Nov 2019 14:19:29 +0100 Subject: [PATCH 001/162] removable drive manager - Windows part --- src/slic3r/GUI/AppConfig.cpp | 5 + src/slic3r/GUI/RemovableDriveManager.cpp | 149 +++++++++++++++++++++++ src/slic3r/GUI/RemovableDriveManager.hpp | 41 +++++++ 3 files changed, 195 insertions(+) create mode 100644 src/slic3r/GUI/RemovableDriveManager.cpp create mode 100644 src/slic3r/GUI/RemovableDriveManager.hpp diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 60f4edf478..67d8bd8cf4 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -21,6 +21,7 @@ #include #include "I18N.hpp" +#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -357,6 +358,10 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { + if (GUI::RemovableDriveManager::getInstance().update()) + { + return GUI::RemovableDriveManager::getInstance().getLastDrivePath(); + } const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp new file mode 100644 index 0000000000..44d4181d1b --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -0,0 +1,149 @@ +#include "RemovableDriveManager.hpp" + +#include +#include +#include +#include + +//#include +//#include "libslic3r/Utils.hpp" + +DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, + 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); + +namespace Slic3r { +namespace GUI { + +std::vector RemovableDriveManager::currentDrives; + +bool RemovableDriveManager::update() +{ + searchForDrives(currentDrives); + return !currentDrives.empty(); +} +void RemovableDriveManager::searchForDrives(std::vector& newDrives) +{ + newDrives.clear(); + newDrives.reserve(26); + DWORD drivesMask = GetLogicalDrives(); + for (size_t i = 0; i < 26; i++) + { + if(drivesMask & (1 << i)) + { + std::string path (1,(char)('A' + i)); + path+=":"; + UINT driveType = GetDriveTypeA(path.c_str()); + //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) + { + newDrives.push_back(DriveData(volumeName, path)); + } + } + } + } + else if(driveType == 3)//disks and usb drives + { + } + } + } + +} + +void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) +{ + currentDrives.clear(); + currentDrives.reserve(26); + for (auto it = newDrives.begin(); it != newDrives.end(); ++it) + { + currentDrives.push_back(*it); + } +} +void RemovableDriveManager::printDrivesToLog() +{ + //std::cout<<"current drives:"<< currentDrives.size() <<"\n"; + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + //BOOST_LOG_TRIVIAL(trace) << boost::format("found disk %1%:") % ('A' + i); + //std::cout << /*std::string((*it).name.begin(), (*it).name.end()) << "(" << */(*it).path << ":/, "; + } + //std::cout << "\n"; +} +bool RemovableDriveManager::isDriveMounted(std::string path) +{ + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + return true; + } + } + return false; +} +void RemovableDriveManager::ejectDrive(std::string path) +{ + if (!update() || !isDriveMounted(path)) + return; + + path = "\\\\.\\"+path; + HANDLE handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if(handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << path << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0,nullptr , 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if(error != 0) + std::cout << "Ejected " << path << "\n"; + else + std::cerr << "Ejecting " << path << " failed "<< deviceControlRetVal << " " << GetLastError() <<" \n"; + + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + currentDrives.erase(it); + break; + } + } +} +std::string RemovableDriveManager::getLastDrivePath() +{ + if (!currentDrives.empty()) + { + return currentDrives.back().path; + } + return ""; +} +void RemovableDriveManager::getAllDrives(std::vector& drives) +{ + drives.clear(); + drives.reserve(26); + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + drives.push_back(*it); + } +} +}} \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp new file mode 100644 index 0000000000..cab58fee6c --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -0,0 +1,41 @@ +#ifndef slic3r_GUI_RemovableDriveManager_hpp_ +#define slic3r_GUI_RemovableDriveManager_hpp_ + +#include +#include + +namespace Slic3r { +namespace GUI { +struct DriveData +{ + std::wstring name; + std::string path; + DriveData(std::wstring n, std::string p):name(n),path(p){} +}; +class RemovableDriveManager +{ +public: + static RemovableDriveManager& getInstance() + { + static RemovableDriveManager instance; + return instance; + } + RemovableDriveManager(RemovableDriveManager const&) = delete; + void operator=(RemovableDriveManager const&) = delete; + + //update() searches for removable devices, returns false if empty. + static bool update(); + static bool isDriveMounted(std::string path); + static void ejectDrive(std::string path); + static std::string getLastDrivePath(); + static void getAllDrives(std::vector& drives); +private: + RemovableDriveManager(){} + static void searchForDrives(std::vector& newDrives); + static void printDrivesToLog(); + static void updateCurrentDrives(const std::vector& newDrives); + static std::vector currentDrives; + +}; +}} +#endif \ No newline at end of file From 4822b577d2af2c37c56ae0a012b59c3177ed7502 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 26 Nov 2019 15:52:18 +0100 Subject: [PATCH 002/162] removable drives manager linux part --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/RemovableDriveManager.cpp | 166 +++++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.hpp | 10 +- 3 files changed, 134 insertions(+), 44 deletions(-) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 6dcbc60b71..bb196d3fde 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -109,6 +109,8 @@ set(SLIC3R_GUI_SOURCES GUI/WipeTowerDialog.hpp GUI/RammingChart.cpp GUI/RammingChart.hpp + GUI/RemovableDriveManager.cpp + GUI/RemovableDriveManager.hpp GUI/BonjourDialog.cpp GUI/BonjourDialog.hpp GUI/ButtonsDescription.cpp diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 44d4181d1b..ae718b7d3a 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,26 +1,34 @@ #include "RemovableDriveManager.hpp" -#include -#include + + #include #include -//#include -//#include "libslic3r/Utils.hpp" +#if _WIN32 +#include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); +#else +//linux includes +#include +#include +#include +#include +#include +#endif namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::currentDrives; -bool RemovableDriveManager::update() -{ - searchForDrives(currentDrives); - return !currentDrives.empty(); -} + + + +#if _WIN32 void RemovableDriveManager::searchForDrives(std::vector& newDrives) { newDrives.clear(); @@ -69,37 +77,6 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) } } - -void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) -{ - currentDrives.clear(); - currentDrives.reserve(26); - for (auto it = newDrives.begin(); it != newDrives.end(); ++it) - { - currentDrives.push_back(*it); - } -} -void RemovableDriveManager::printDrivesToLog() -{ - //std::cout<<"current drives:"<< currentDrives.size() <<"\n"; - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - //BOOST_LOG_TRIVIAL(trace) << boost::format("found disk %1%:") % ('A' + i); - //std::cout << /*std::string((*it).name.begin(), (*it).name.end()) << "(" << */(*it).path << ":/, "; - } - //std::cout << "\n"; -} -bool RemovableDriveManager::isDriveMounted(std::string path) -{ - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - if ((*it).path == path) - { - return true; - } - } - return false; -} void RemovableDriveManager::ejectDrive(std::string path) { if (!update() || !isDriveMounted(path)) @@ -129,6 +106,115 @@ void RemovableDriveManager::ejectDrive(std::string path) } } } +#else +void RemovableDriveManager::searchForDrives(std::vector& newDrives) +{ + struct stat buf; + std::string path(std::getenv("USER")); + std::string pp(path); + + newDrives.clear(); + newDrives.reserve(26); + + //search /media/* folder + stat("/media/",&buf); + std::cout << "/media ID: " <& newDrives,const std::string path, const dev_t parentDevID) +{ + glob_t globbuf; + globbuf.gl_offs = 2; + std::cout<<"searching "<& newDrives) +{ + currentDrives.clear(); + currentDrives.reserve(26); + for (auto it = newDrives.begin(); it != newDrives.end(); ++it) + { + currentDrives.push_back(*it); + } +} +bool RemovableDriveManager::isDriveMounted(std::string path) +{ + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + return true; + } + } + return false; +} + std::string RemovableDriveManager::getLastDrivePath() { if (!currentDrives.empty()) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index cab58fee6c..c503fdf187 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -8,9 +8,9 @@ namespace Slic3r { namespace GUI { struct DriveData { - std::wstring name; + std::string name; std::string path; - DriveData(std::wstring n, std::string p):name(n),path(p){} + DriveData(std::string n, std::string p):name(n),path(p){} }; class RemovableDriveManager { @@ -32,10 +32,12 @@ public: private: RemovableDriveManager(){} static void searchForDrives(std::vector& newDrives); - static void printDrivesToLog(); static void updateCurrentDrives(const std::vector& newDrives); static std::vector currentDrives; - +#if _WIN32 +#else + static void searchPath(std::vector& newDrives,const std::string path, const dev_t parentDevID); +#endif }; }} #endif \ No newline at end of file From fdf159af42919a7d07288559732e93641b7e2588 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 11:33:36 +0100 Subject: [PATCH 003/162] refactoring --- src/slic3r/GUI/AppConfig.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.cpp | 116 ++++++++++------------- src/slic3r/GUI/RemovableDriveManager.hpp | 15 ++- 3 files changed, 58 insertions(+), 75 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 67d8bd8cf4..320f337515 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -360,7 +360,7 @@ std::string AppConfig::get_last_output_dir(const std::string &alt) const { if (GUI::RemovableDriveManager::getInstance().update()) { - return GUI::RemovableDriveManager::getInstance().getLastDrivePath(); + return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); } const auto it = m_storage.find(""); if (it != m_storage.end()) { diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ae718b7d3a..53515ccdcb 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,14 +1,12 @@ #include "RemovableDriveManager.hpp" - - - #include #include - +#include "boost/nowide/convert.hpp" #if _WIN32 #include #include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); #else @@ -23,16 +21,13 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, namespace Slic3r { namespace GUI { -std::vector RemovableDriveManager::currentDrives; - - - +std::vector RemovableDriveManager::m_current_drives; #if _WIN32 -void RemovableDriveManager::searchForDrives(std::vector& newDrives) +void RemovableDriveManager::search_for_drives() { - newDrives.clear(); - newDrives.reserve(26); + m_current_drives.clear(); + m_current_drives.reserve(26); DWORD drivesMask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { @@ -65,7 +60,7 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) //std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n"; if (freeSpace.QuadPart > 0) { - newDrives.push_back(DriveData(volumeName, path)); + m_current_drives.push_back(DriveData(boost::nowide::narrow(volumeName), path)); } } } @@ -77,49 +72,51 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) } } -void RemovableDriveManager::ejectDrive(std::string path) +void RemovableDriveManager::eject_drive(const std::string &path) { - if (!update() || !isDriveMounted(path)) - return; - path = "\\\\.\\"+path; - HANDLE handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - if(handle == INVALID_HANDLE_VALUE) - { - std::cerr << "Ejecting " << path << " failed " << GetLastError() << " \n"; + //if (!update() || !is_drive_mounted(path)) + if(m_current_drives.empty()) return; - } - DWORD deviceControlRetVal(0); - BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0,nullptr , 0, &deviceControlRetVal, nullptr); - CloseHandle(handle); - if(error != 0) - std::cout << "Ejected " << path << "\n"; - else - std::cerr << "Ejecting " << path << " failed "<< deviceControlRetVal << " " << GetLastError() <<" \n"; - - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { - currentDrives.erase(it); + std::string mpath = "\\\\.\\" + path; + HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if (handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if (error != 0) + std::cout << "Ejected " << mpath << "\n"; + else + std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + + + m_current_drives.erase(it); break; } } } #else -void RemovableDriveManager::searchForDrives(std::vector& newDrives) +void RemovableDriveManager::search_for_drives() { struct stat buf; std::string path(std::getenv("USER")); std::string pp(path); - newDrives.clear(); - newDrives.reserve(26); + m_current_drives.clear(); + m_current_Drives.reserve(26); //search /media/* folder stat("/media/",&buf); std::cout << "/media ID: " <& newDrives) stat(pp.c_str() ,&buf); std::cout << pp <<" ID: " <& newDrives,const std::string path, const dev_t parentDevID) +void RemovableDriveManager::search_path(const std::string &path,const dev_t &parentDevID) { glob_t globbuf; globbuf.gl_offs = 2; @@ -159,17 +156,17 @@ void RemovableDriveManager::searchPath(std::vector& newDrives,const s std::cout << buf.st_dev << "\n"; if(buf.st_dev != parentDevID)// not same file system { - newDrives.push_back(DriveData(name,globbuf.gl_pathv[i])); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); } } globfree(&globbuf); } -void RemovableDriveManager::ejectDrive(std::string path) +void RemovableDriveManager::eject_drive(const std::string &path) { - if (currentDrives.empty()) + if (m_current_drives.empty()) return; - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if((*it).path == path) { @@ -180,7 +177,7 @@ void RemovableDriveManager::ejectDrive(std::string path) int errsv = errno; std::cerr<<"Ejecting failed Error "<< errsv<<"\n"; } - currentDrives.erase(it); + m_current_drives.erase(it); break; } @@ -190,22 +187,14 @@ void RemovableDriveManager::ejectDrive(std::string path) #endif bool RemovableDriveManager::update() { - searchForDrives(currentDrives); - return !currentDrives.empty(); + search_for_drives(); + return !m_current_drives.empty(); } -void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) + +bool RemovableDriveManager::is_drive_mounted(const std::string &path) { - currentDrives.clear(); - currentDrives.reserve(26); - for (auto it = newDrives.begin(); it != newDrives.end(); ++it) - { - currentDrives.push_back(*it); - } -} -bool RemovableDriveManager::isDriveMounted(std::string path) -{ - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { @@ -215,21 +204,16 @@ bool RemovableDriveManager::isDriveMounted(std::string path) return false; } -std::string RemovableDriveManager::getLastDrivePath() +std::string RemovableDriveManager::get_last_drive_path() { - if (!currentDrives.empty()) + if (!m_current_drives.empty()) { - return currentDrives.back().path; + return m_current_drives.back().path; } return ""; } -void RemovableDriveManager::getAllDrives(std::vector& drives) +std::vector RemovableDriveManager::get_all_drives() { - drives.clear(); - drives.reserve(26); - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - drives.push_back(*it); - } + return m_current_drives; } }} \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c503fdf187..8270c0f0fb 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -25,18 +25,17 @@ public: //update() searches for removable devices, returns false if empty. static bool update(); - static bool isDriveMounted(std::string path); - static void ejectDrive(std::string path); - static std::string getLastDrivePath(); - static void getAllDrives(std::vector& drives); + static bool is_drive_mounted(const std::string &path); + static void eject_drive(const std::string &path); + static std::string get_last_drive_path(); + static std::vector get_all_drives(); private: RemovableDriveManager(){} - static void searchForDrives(std::vector& newDrives); - static void updateCurrentDrives(const std::vector& newDrives); - static std::vector currentDrives; + static void search_for_drives(); + static std::vector m_current_drives; #if _WIN32 #else - static void searchPath(std::vector& newDrives,const std::string path, const dev_t parentDevID); + static void search_path(const std::string &path, const dev_t &parentDevID); #endif }; }} From 97a9f245f96617dfd1fb74c1262911abf1b68108 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 13:30:45 +0100 Subject: [PATCH 004/162] check if last path is on rem drive --- src/slic3r/GUI/AppConfig.cpp | 6 +---- src/slic3r/GUI/Plater.cpp | 9 ++++++- src/slic3r/GUI/RemovableDriveManager.cpp | 30 +++++++++++++++++++++++- src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 320f337515..16f0459664 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -21,7 +21,6 @@ #include #include "I18N.hpp" -#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -358,10 +357,7 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { - if (GUI::RemovableDriveManager::getInstance().update()) - { - return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); - } + const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 789271581e..bbfa9d9328 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -77,6 +77,7 @@ #include "../Utils/FixModelByWin10.hpp" #include "../Utils/UndoRedo.hpp" #include "../Utils/Thread.hpp" +#include "RemovableDriveManager.hpp" #include // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" @@ -4549,7 +4550,13 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - + if (GUI::RemovableDriveManager::getInstance().update()) + { + if (!RemovableDriveManager::getInstance().is_path_on_removable_drive(start_dir)) + { + start_dir = RemovableDriveManager::getInstance().get_last_drive_path(); + } + } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), start_dir, from_path(default_output_file.filename()), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 53515ccdcb..776334bf22 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); #else @@ -208,7 +209,11 @@ std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { +#if _WIN32 + return m_current_drives.back().path + "\\"; +#else return m_current_drives.back().path; +#endif } return ""; } @@ -216,4 +221,27 @@ std::vector RemovableDriveManager::get_all_drives() { return m_current_drives; } -}} \ No newline at end of file +#if _WIN32 +bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path) +{ + if (m_current_drives.empty()) + return false; + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return true; + } + return false; +} +#else +bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path, const std::string& drive) +{ + if (m_current_drives.empty()) + return false; + + return false; +} +#endif +}}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 8270c0f0fb..3de9d72cee 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -29,6 +29,7 @@ public: static void eject_drive(const std::string &path); static std::string get_last_drive_path(); static std::vector get_all_drives(); + static bool is_path_on_removable_drive(const std::string &path); private: RemovableDriveManager(){} static void search_for_drives(); From 1cd06e32675eea22253312629d2d1ef0b75850d4 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 14:30:10 +0100 Subject: [PATCH 005/162] prev commit linux part --- src/slic3r/GUI/RemovableDriveManager.cpp | 139 ++++++++++++----------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 776334bf22..2d1f4ba6f2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -29,46 +29,43 @@ void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); m_current_drives.reserve(26); - DWORD drivesMask = GetLogicalDrives(); + DWORD drives_mask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { - if(drivesMask & (1 << i)) + if(drives_mask & (1 << i)) { std::string path (1,(char)('A' + i)); path+=":"; - UINT driveType = GetDriveTypeA(path.c_str()); + UINT drive_type = GetDriveTypeA(path.c_str()); //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) + if (free_space.QuadPart > 0) { - m_current_drives.push_back(DriveData(boost::nowide::narrow(volumeName), path)); + m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); } } } } - else if(driveType == 3)//disks and usb drives - { - } } } @@ -93,10 +90,10 @@ void RemovableDriveManager::eject_drive(const std::string &path) DWORD deviceControlRetVal(0); BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); CloseHandle(handle); - if (error != 0) - std::cout << "Ejected " << mpath << "\n"; - else + if (error == 0) + { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + } m_current_drives.erase(it); @@ -104,6 +101,19 @@ void RemovableDriveManager::eject_drive(const std::string &path) } } } +bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) +{ + if (m_current_drives.empty()) + return false; + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return true; + } + return false; +} #else void RemovableDriveManager::search_for_drives() { @@ -112,11 +122,11 @@ void RemovableDriveManager::search_for_drives() std::string pp(path); m_current_drives.clear(); - m_current_Drives.reserve(26); + m_current_drives.reserve(26); //search /media/* folder stat("/media/",&buf); - std::cout << "/media ID: " < RemovableDriveManager::get_all_drives() return m_current_drives; } #if _WIN32 -bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path) -{ - if (m_current_drives.empty()) - return false; - int letter = PathGetDriveNumberA(path.c_str()); - for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) - { - char drive = (*it).path[0]; - if (drive == ('A' + letter)) - return true; - } - return false; -} -#else -bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path, const std::string& drive) -{ - if (m_current_drives.empty()) - return false; - return false; -} +#else + #endif }}//namespace Slicer::Gui:: \ No newline at end of file From 4337b65f52e3ed761481cfafbd5c0aeb2e034d42 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 15:47:37 +0100 Subject: [PATCH 006/162] rdm update every 2 seconds --- src/slic3r/GUI/GUI_App.cpp | 2 ++ src/slic3r/GUI/RemovableDriveManager.cpp | 15 ++++++++++++++- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a74c6b0c06..35c11f0211 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -46,6 +46,7 @@ #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" #include "UpdateDialogs.hpp" +#include "RemovableDriveManager.hpp" #ifdef __WXMSW__ #include @@ -269,6 +270,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); + RemovableDriveManager::getInstance().update(wxGetLocalTime()); // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 2d1f4ba6f2..235e1ccbe8 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -23,6 +23,7 @@ namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::m_current_drives; +long RemovableDriveManager::m_last_update = 0; #if _WIN32 void RemovableDriveManager::search_for_drives() @@ -215,8 +216,20 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) return false; } #endif -bool RemovableDriveManager::update() +bool RemovableDriveManager::update(long time) { + if(time != 0) //time = 0 is forced update + { + long diff = m_last_update - time; + if(diff <= -2) + { + m_last_update = time; + }else + { + return false; // return value shouldnt matter if update didnt run + } + } + std::cout << "RDM update " << m_last_update <<"\n"; search_for_drives(); return !m_current_drives.empty(); } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 3de9d72cee..c83b8033c9 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,7 +24,7 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - static bool update(); + static bool update(long time = 0); //time = 0 is forced update static bool is_drive_mounted(const std::string &path); static void eject_drive(const std::string &path); static std::string get_last_drive_path(); @@ -34,6 +34,7 @@ private: RemovableDriveManager(){} static void search_for_drives(); static std::vector m_current_drives; + static long m_last_update; #if _WIN32 #else static void search_path(const std::string &path, const dev_t &parentDevID); From b7a5020196ecb42179825eb3504604f2e99e802d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 28 Nov 2019 13:38:08 +0100 Subject: [PATCH 007/162] add_callback function --- src/slic3r/GUI/RemovableDriveManager.cpp | 65 ++++++++++++++++++++---- src/slic3r/GUI/RemovableDriveManager.hpp | 6 ++- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 235e1ccbe8..a1a5d7dd92 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -23,7 +23,8 @@ namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::m_current_drives; -long RemovableDriveManager::m_last_update = 0; +std::vector> RemovableDriveManager::m_callbacks; + #if _WIN32 void RemovableDriveManager::search_for_drives() @@ -69,7 +70,7 @@ void RemovableDriveManager::search_for_drives() } } } - + //std::cout << "found drives:" << m_current_drives.size() << "\n"; } void RemovableDriveManager::eject_drive(const std::string &path) { @@ -115,6 +116,25 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } return false; } +void RemovableDriveManager::register_window() +{ + /* + WNDCLASSEX wndClass; + + wndClass.cbSize = sizeof(WNDCLASSEX); + wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); + wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback); + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); + wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192)); + wndClass.hCursor = LoadCursor(0, IDC_ARROW); + wndClass.lpszClassName = L"SlicerWindowClass"; + wndClass.lpszMenuName = NULL; + wndClass.hIconSm = wndClass.hIcon; + */ +} #else void RemovableDriveManager::search_for_drives() { @@ -218,19 +238,29 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) #endif bool RemovableDriveManager::update(long time) { + static long last_update = 0; + if(last_update == 0) + { + //add_callback(std::bind(&RemovableDriveManager::print, RemovableDriveManager::getInstance())); + add_callback([](void) { print(); }); +#if _WIN32 + register_window(); +#endif + } if(time != 0) //time = 0 is forced update { - long diff = m_last_update - time; + long diff = last_update - time; if(diff <= -2) { - m_last_update = time; + last_update = time; }else { return false; // return value shouldnt matter if update didnt run } } - std::cout << "RDM update " << m_last_update <<"\n"; + //std::cout << "RDM update " << last_update <<"\n"; search_for_drives(); + check_and_notify(); return !m_current_drives.empty(); } @@ -263,9 +293,24 @@ std::vector RemovableDriveManager::get_all_drives() { return m_current_drives; } -#if _WIN32 - -#else - -#endif +void RemovableDriveManager::check_and_notify() +{ + static int number_of_drives = 0; + if(number_of_drives != m_current_drives.size()) + { + for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) + { + (*it)(); + } + number_of_drives = m_current_drives.size(); + } +} +void RemovableDriveManager::add_callback(std::function callback) +{ + m_callbacks.push_back(callback); +} +void RemovableDriveManager::print() +{ + std::cout << "notified\n"; +} }}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c83b8033c9..9f3ebf326b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -30,12 +30,16 @@ public: static std::string get_last_drive_path(); static std::vector get_all_drives(); static bool is_path_on_removable_drive(const std::string &path); + static void add_callback(std::function callback); + static void print(); private: RemovableDriveManager(){} static void search_for_drives(); + static void check_and_notify(); static std::vector m_current_drives; - static long m_last_update; + static std::vector> m_callbacks; #if _WIN32 + static void register_window(); #else static void search_path(const std::string &path, const dev_t &parentDevID); #endif From 7301b4f7dd59138e8a44f1cc68996083db0dda9c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 28 Nov 2019 13:50:58 +0100 Subject: [PATCH 008/162] refactoring --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 ++--- src/slic3r/GUI/RemovableDriveManager.cpp | 6 ++--- src/slic3r/GUI/RemovableDriveManager.hpp | 30 ++++++++++++------------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 35c11f0211..10eb4ab59b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -270,7 +270,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::getInstance().update(wxGetLocalTime()); + RemovableDriveManager::get_instance().update(wxGetLocalTime()); // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bbfa9d9328..74b2d12391 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4550,11 +4550,11 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - if (GUI::RemovableDriveManager::getInstance().update()) + if (GUI::RemovableDriveManager::get_instance().update()) { - if (!RemovableDriveManager::getInstance().is_path_on_removable_drive(start_dir)) + if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) { - start_dir = RemovableDriveManager::getInstance().get_last_drive_path(); + start_dir = RemovableDriveManager::get_instance().get_last_drive_path(); } } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index a1a5d7dd92..777085165d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -22,8 +22,8 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, namespace Slic3r { namespace GUI { -std::vector RemovableDriveManager::m_current_drives; -std::vector> RemovableDriveManager::m_callbacks; +//std::vector RemovableDriveManager::m_current_drives; +//std::vector> RemovableDriveManager::m_callbacks; #if _WIN32 @@ -242,7 +242,7 @@ bool RemovableDriveManager::update(long time) if(last_update == 0) { //add_callback(std::bind(&RemovableDriveManager::print, RemovableDriveManager::getInstance())); - add_callback([](void) { print(); }); + add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); #endif diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 9f3ebf326b..f3abc42073 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -15,7 +15,7 @@ struct DriveData class RemovableDriveManager { public: - static RemovableDriveManager& getInstance() + static RemovableDriveManager& get_instance() { static RemovableDriveManager instance; return instance; @@ -24,24 +24,24 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - static bool update(long time = 0); //time = 0 is forced update - static bool is_drive_mounted(const std::string &path); - static void eject_drive(const std::string &path); - static std::string get_last_drive_path(); - static std::vector get_all_drives(); - static bool is_path_on_removable_drive(const std::string &path); - static void add_callback(std::function callback); - static void print(); + bool update(long time = 0); //time = 0 is forced update + bool is_drive_mounted(const std::string &path); + void eject_drive(const std::string &path); + std::string get_last_drive_path(); + std::vector get_all_drives(); + bool is_path_on_removable_drive(const std::string &path); + void add_callback(std::function callback); + void print(); private: RemovableDriveManager(){} - static void search_for_drives(); - static void check_and_notify(); - static std::vector m_current_drives; - static std::vector> m_callbacks; + void search_for_drives(); + void check_and_notify(); + std::vector m_current_drives; + std::vector> m_callbacks; #if _WIN32 - static void register_window(); + void register_window(); #else - static void search_path(const std::string &path, const dev_t &parentDevID); + void search_path(const std::string &path, const dev_t &parentDevID); #endif }; }} From 82baaf291eaaaeeea061003602504c8c7f4ee7ea Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 28 Nov 2019 16:35:22 +0100 Subject: [PATCH 009/162] search for rd as root --- src/slic3r/GUI/RemovableDriveManager.cpp | 103 +++++++++++++---------- src/slic3r/GUI/RemovableDriveManager.hpp | 3 +- 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 777085165d..4368d06b64 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,6 +1,5 @@ #include "RemovableDriveManager.hpp" #include -#include #include "boost/nowide/convert.hpp" #if _WIN32 @@ -17,6 +16,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, #include #include #include +#include #endif namespace Slic3r { @@ -96,8 +96,6 @@ void RemovableDriveManager::eject_drive(const std::string &path) { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; } - - m_current_drives.erase(it); break; } @@ -138,65 +136,85 @@ void RemovableDriveManager::register_window() #else void RemovableDriveManager::search_for_drives() { - struct stat buf; - std::string path(std::getenv("USER")); - std::string pp(path); - + m_current_drives.clear(); m_current_drives.reserve(26); //search /media/* folder - stat("/media/",&buf); - //std::cout << "/media ID: " <pw_name; + pp = path; + //search /media/USERNAME/* folder + pp = "/media/"+pp; + path = "/media/" + path + "/*"; + search_path(path, pp); - stat(pp.c_str() ,&buf); - //std::cout << pp <<" ID: " < RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - static int number_of_drives = 0; + static size_t number_of_drives = 0; if(number_of_drives != m_current_drives.size()) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index f3abc42073..43e47a0867 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -41,7 +41,8 @@ private: #if _WIN32 void register_window(); #else - void search_path(const std::string &path, const dev_t &parentDevID); + void search_path(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; }} From 0eb8cb3fa159028f9ddfe3fd2428a864218b5782 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 3 Dec 2019 10:09:53 +0100 Subject: [PATCH 010/162] linux eject --- src/slic3r/GUI/GUI_App.cpp | 1 + src/slic3r/GUI/RemovableDriveManager.cpp | 29 ++++++++++++++---------- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 10eb4ab59b..c36c2748dd 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -271,6 +271,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); RemovableDriveManager::get_instance().update(wxGetLocalTime()); + // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 4368d06b64..ec730692fa 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -20,8 +20,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, #endif namespace Slic3r { -namespace GUI { - +namespace GUI { //std::vector RemovableDriveManager::m_current_drives; //std::vector> RemovableDriveManager::m_callbacks; @@ -95,7 +94,10 @@ void RemovableDriveManager::eject_drive(const std::string &path) if (error == 0) { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + return; } + + m_current_drives.erase(it); break; } @@ -179,7 +181,7 @@ void RemovableDriveManager::search_for_drives() } - std::cout << "found drives:" < RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - static size_t number_of_drives = 0; - if(number_of_drives != m_current_drives.size()) + //std::cout<<"drives count: "< callback) { diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 43e47a0867..b465b1c1b8 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -33,11 +33,12 @@ public: void add_callback(std::function callback); void print(); private: - RemovableDriveManager(){} + RemovableDriveManager():m_drives_count(0){} void search_for_drives(); void check_and_notify(); std::vector m_current_drives; std::vector> m_callbacks; + size_t m_drives_count; #if _WIN32 void register_window(); #else From 55409b0e96e804c4733956f74a23ef70a1c3945b Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 3 Dec 2019 10:55:38 +0100 Subject: [PATCH 011/162] windows paths --- src/slic3r/GUI/RemovableDriveManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ec730692fa..9b3020e79e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -62,6 +62,7 @@ void RemovableDriveManager::search_for_drives() //std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n"; if (free_space.QuadPart > 0) { + path += "\\"; m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); } } @@ -82,6 +83,8 @@ void RemovableDriveManager::eject_drive(const std::string &path) if ((*it).path == path) { std::string mpath = "\\\\.\\" + path; + mpath = mpath.substr(0, mpath.size() - 1); + std::cout << "Ejecting " << mpath << "\n"; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { @@ -299,11 +302,11 @@ std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { -#if _WIN32 - return m_current_drives.back().path + "\\"; -#else +//#if _WIN32 +// return m_current_drives.back().path + "\\"; +//#else return m_current_drives.back().path; -#endif +//#endif } return ""; } From 14fdf429ea3bb30ef9f1622912cab81efe696785 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 10:05:18 +0100 Subject: [PATCH 012/162] osx search for drives --- src/slic3r/GUI/RemovableDriveManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 9b3020e79e..bdc1727403 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -148,6 +148,9 @@ void RemovableDriveManager::search_for_drives() //search /media/* folder search_path("/media/*", "/media"); + //search /Volumes/* folder (OSX) + search_path("/Volumes/*", "/Volumes"); + std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; From 79cdb0ab07e8e1c62b5583384e33561e9d93aa76 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 11:47:47 +0100 Subject: [PATCH 013/162] linux owner checking --- src/slic3r/GUI/RemovableDriveManager.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index bdc1727403..99520b8429 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -154,7 +154,10 @@ void RemovableDriveManager::search_for_drives() std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; - if(path == "root"){ //if program is run with sudo, we have to search for all users + //if program is run with sudo, we have to search for all users + // but do we want that? + /* + if(path == "root"){ while (true) { passwd* entry = getpwent(); if (!entry) { @@ -174,6 +177,7 @@ void RemovableDriveManager::search_for_drives() } endpwent(); }else + */ { //search /media/USERNAME/* folder pp = "/media/"+pp; @@ -187,7 +191,7 @@ void RemovableDriveManager::search_for_drives() } - //std::cout << "found drives:" <pw_name == username) + { + std::string name = basename(globbuf.gl_pathv[i]); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); + } + } } } }else From fd7d75028a28f78b8d5c16c8d3b8a5269f7680e3 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:10:08 +0100 Subject: [PATCH 014/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 99520b8429..e1ab1626c5 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -248,6 +248,15 @@ void RemovableDriveManager::eject_drive(const std::string &path) { if((*it).path == path) { + + std::string correct_path(path); + for (size_t i = 0; i < correct_path.size(); ++i) + { + if(correct_path[i]==' ') + { + correct_path = correct_path.insert(i,"\\"); + } + } std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; std::string command = "umount "; command += (*it).path; @@ -301,6 +310,7 @@ bool RemovableDriveManager::update(long time) } search_for_drives(); check_and_notify(); + eject_drive(m_current_drives.back().path); return !m_current_drives.empty(); } From 0b015b0864911f45aaa9e6feb2c4c630575746c3 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:13:18 +0100 Subject: [PATCH 015/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index e1ab1626c5..3ff5735f91 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -255,6 +255,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) if(correct_path[i]==' ') { correct_path = correct_path.insert(i,"\\"); + i++; } } std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; From 1c9dddeb2b923c2444def337ab0f7f0be34a099d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:18:08 +0100 Subject: [PATCH 016/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 3ff5735f91..7216763eec 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -254,13 +254,13 @@ void RemovableDriveManager::eject_drive(const std::string &path) { if(correct_path[i]==' ') { - correct_path = correct_path.insert(i,"\\"); + correct_path = correct_path.insert(i,1,'\\'); i++; } } - std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; + std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<"\n"; std::string command = "umount "; - command += (*it).path; + command += correct_path; int err = system(command.c_str()); if(err) { From 9a301ac98df7ffecfa1e86dbc66d2f1259a9a3dd Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:21:41 +0100 Subject: [PATCH 017/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7216763eec..c859a5d872 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -258,7 +258,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) i++; } } - std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<"\n"; + std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; std::string command = "umount "; command += correct_path; int err = system(command.c_str()); From 1f6d2c87b85855e4998e7770a75499e3665652c9 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:30:25 +0100 Subject: [PATCH 018/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index c859a5d872..3d77606c81 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -259,7 +259,13 @@ void RemovableDriveManager::eject_drive(const std::string &path) } } std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; - std::string command = "umount "; + + std::string command = ""; +#if __APPLE__ + command = "diskutil unmount "; +#else + command = "umount "; +#endif command += correct_path; int err = system(command.c_str()); if(err) From 0a4b2331a15c93cd503117b7110d3ed5c4013d4d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:43:28 +0100 Subject: [PATCH 019/162] comment testing lines --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 3d77606c81..0665e57dc2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -317,7 +317,7 @@ bool RemovableDriveManager::update(long time) } search_for_drives(); check_and_notify(); - eject_drive(m_current_drives.back().path); + //eject_drive(m_current_drives.back().path); return !m_current_drives.empty(); } From 18be3ffb5f6db881353d12331c2022f304220be9 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 15:27:33 +0100 Subject: [PATCH 020/162] refactoring --- src/slic3r/GUI/RemovableDriveManager.cpp | 14 +++++++------- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 0665e57dc2..a655425fc4 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -121,6 +121,7 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } void RemovableDriveManager::register_window() { + //std::cout << "Registering for device notification\n"; /* WNDCLASSEX wndClass; @@ -137,6 +138,7 @@ void RemovableDriveManager::register_window() wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; */ + //std::cout << "Failed\n"; } #else void RemovableDriveManager::search_for_drives() @@ -191,7 +193,7 @@ void RemovableDriveManager::search_for_drives() } - std::cout << "found drives:" < callback); void print(); private: - RemovableDriveManager():m_drives_count(0){} + RemovableDriveManager():m_drives_count(0),m_last_update(0){} void search_for_drives(); void check_and_notify(); std::vector m_current_drives; std::vector> m_callbacks; size_t m_drives_count; + long m_last_update; #if _WIN32 void register_window(); #else From 5f54856be0ae9dbde03595101e040f9fd45afab7 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 5 Dec 2019 14:07:02 +0100 Subject: [PATCH 021/162] last path functions --- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/Plater.cpp | 2 + src/slic3r/GUI/RemovableDriveManager.cpp | 174 +++++++++++++++++++++-- src/slic3r/GUI/RemovableDriveManager.hpp | 12 +- 4 files changed, 173 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index c36c2748dd..37753a0dea 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -270,7 +270,8 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime()); + //RemovableDriveManager::get_instance().update(wxGetLocalTime()); + std::cout << RemovableDriveManager::get_instance().is_last_drive_removed() << "\n"; // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5d967cb6c0..d1ce50f41f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4575,9 +4575,11 @@ void Plater::export_gcode() fs::path path = into_path(dlg.GetPath()); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = std::move(path); + RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); } if (! output_path.empty()) p->export_gcode(std::move(output_path), PrintHostJob()); + } void Plater::export_stl(bool extended, bool selection_only) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index a655425fc4..146bebc119 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -7,8 +7,11 @@ #include #include #include -DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, - 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); + +//#include +//GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, +// 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; + #else //linux includes #include @@ -26,6 +29,7 @@ namespace GUI { #if _WIN32 +//INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); @@ -84,7 +88,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) { std::string mpath = "\\\\.\\" + path; mpath = mpath.substr(0, mpath.size() - 1); - std::cout << "Ejecting " << mpath << "\n"; + //std::cout << "Ejecting " << mpath << "\n"; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { @@ -119,10 +123,24 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } return false; } +std::string RemovableDriveManager::get_drive_from_path(const std::string& path) +{ + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return (*it).path; + } + return ""; +} void RemovableDriveManager::register_window() { - //std::cout << "Registering for device notification\n"; /* + std::cout << "Registering for device notification\n"; + + + WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); @@ -134,12 +152,109 @@ void RemovableDriveManager::register_window() wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192)); wndClass.hCursor = LoadCursor(0, IDC_ARROW); - wndClass.lpszClassName = L"SlicerWindowClass"; + wndClass.lpszClassName = L"PrusaSlicer_aux_class"; wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; - */ - //std::cout << "Failed\n"; + + HINSTANCE hInstanceExe = GetModuleHandle(NULL); + + HWND hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE | WS_EX_APPWINDOW, + L"PrusaSlicer_aux_class", + L"PrusaSlicer_aux_wnd", + WS_OVERLAPPEDWINDOW, // style + CW_USEDEFAULT, 0, + 640, 480, + NULL, NULL, + hInstanceExe, + NULL); +*/ } +/* +INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT lRet = 1; + static HDEVNOTIFY hDeviceNotify; + static HWND hEditWnd; + static ULONGLONG msgCount = 0; + + switch (message) + { + case WM_CREATE: + + + DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; + + ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); + NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + NotificationFilter.dbcc_classguid = WceusbshGUID; + + hDeviceNotify = RegisterDeviceNotification( + hWnd, // events recipient + &NotificationFilter, // type of device + DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle + ); + break; + + + + case WM_DEVICECHANGE: + { + std::cout << "WM_DEVICECHANGE\n"; + /* + // This is the actual message from the interface via Windows messaging. + // This code includes some additional decoding for this particular device type + // and some common validation checks. + // + // Note that not all devices utilize these optional parameters in the same + // way. Refer to the extended information for your particular device type + // specified by your GUID. + // + PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; + TCHAR strBuff[256]; + + // Output some messages to the window. + switch (wParam) + { + case DBT_DEVICEARRIVAL: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount); + break; + case DBT_DEVICEREMOVECOMPLETE: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount); + break; + case DBT_DEVNODES_CHANGED: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount); + break; + default: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"), + msgCount, wParam); + break; + } + OutputMessage(hEditWnd, wParam, (LPARAM)strBuff); + / + } + break; + default: + // Send all other messages on to the default windows handler. + lRet = DefWindowProc(hWnd, message, wParam, lParam); + break; + } + return lRet; +} +*/ #else void RemovableDriveManager::search_for_drives() { @@ -294,6 +409,16 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } return false; } +std::string RemovableDriveManager::get_drive_from_path(const std::string& path) +{ + //check if same filesystem + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + if (compare_filesystem_id(path, (*it).path)) + return (*it).path; + } + return ""; +} #endif bool RemovableDriveManager::update(long time) { @@ -301,7 +426,7 @@ bool RemovableDriveManager::update(long time) { //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 - register_window(); + //register_window(); #endif } if(time != 0) //time = 0 is forced update @@ -338,11 +463,9 @@ std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { -//#if _WIN32 -// return m_current_drives.back().path + "\\"; -//#else + if (m_last_save_path != "") + return m_last_save_path; return m_current_drives.back().path; -//#endif } return ""; } @@ -356,9 +479,12 @@ void RemovableDriveManager::check_and_notify() if(m_drives_count != m_current_drives.size()) { //std::cout<<" vs "<< m_current_drives.size(); - for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) + if(m_drives_count > m_current_drives.size()) { - (*it)(); + for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) + { + (*it)(); + } } m_drives_count = m_current_drives.size(); } @@ -368,6 +494,26 @@ void RemovableDriveManager::add_callback(std::function callback) { m_callbacks.push_back(callback); } +void RemovableDriveManager::set_last_save_path(const std::string& path) +{ + std::string last_drive = get_drive_from_path(path); + if(last_drive != "") + { + m_last_save_path = last_drive; + } +} +bool RemovableDriveManager::is_last_drive_removed() +{ + if(m_last_save_path == "") + { + return true; + } + return !is_drive_mounted(m_last_save_path); +} +void RemovableDriveManager::reset_last_save_path() +{ + m_last_save_path = ""; +} void RemovableDriveManager::print() { std::cout << "notified\n"; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c65a7fe625..be5ae5968e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,24 +24,30 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - bool update(long time = 0); //time = 0 is forced update + bool update(long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); - void add_callback(std::function callback); + void add_callback(std::function callback); // callback will notify every drive removal. to see if it was last used drive call is_last_drive_removed() + void set_last_save_path(const std::string &path); + bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); + void reset_last_save_path(); void print(); private: - RemovableDriveManager():m_drives_count(0),m_last_update(0){} + RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} void search_for_drives(); void check_and_notify(); + std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" std::vector m_current_drives; std::vector> m_callbacks; size_t m_drives_count; long m_last_update; + std::string m_last_save_path; #if _WIN32 void register_window(); + //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); From 822ffa6c86076cd4f49731c09b84b4248104976f Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 5 Dec 2019 16:22:54 +0100 Subject: [PATCH 022/162] last save path --- src/slic3r/GUI/GUI_App.cpp | 7 ++++--- src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++++++++-- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 37753a0dea..ed5371e669 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -270,9 +270,10 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - //RemovableDriveManager::get_instance().update(wxGetLocalTime()); - std::cout << RemovableDriveManager::get_instance().is_last_drive_removed() << "\n"; - + + RemovableDriveManager::get_instance().update(wxGetLocalTime()); + + // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 146bebc119..e94ea6918a 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -420,11 +420,11 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) return ""; } #endif -bool RemovableDriveManager::update(long time) +bool RemovableDriveManager::update(const long time) { if(m_last_update == 0) { - //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); + add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 //register_window(); #endif @@ -510,12 +510,18 @@ bool RemovableDriveManager::is_last_drive_removed() } return !is_drive_mounted(m_last_save_path); } +bool RemovableDriveManager::is_last_drive_removed_with_update(const long time) +{ + update(time); + return is_last_drive_removed(); +} void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } void RemovableDriveManager::print() { + //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; std::cout << "notified\n"; } }}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index be5ae5968e..906667244b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,7 +24,7 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - bool update(long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_drive_path(); @@ -33,6 +33,7 @@ public: void add_callback(std::function callback); // callback will notify every drive removal. to see if it was last used drive call is_last_drive_removed() void set_last_save_path(const std::string &path); bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); + bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); void print(); private: From 0f18e7e7ecb81e896f19bc9a5704b133225198bf Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 6 Dec 2019 13:17:36 +0100 Subject: [PATCH 023/162] callback only for used device --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index e94ea6918a..6581d53614 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -479,7 +479,7 @@ void RemovableDriveManager::check_and_notify() if(m_drives_count != m_current_drives.size()) { //std::cout<<" vs "<< m_current_drives.size(); - if(m_drives_count > m_current_drives.size()) + if(m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 906667244b..741b4424ab 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -30,7 +30,7 @@ public: std::string get_last_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); - void add_callback(std::function callback); // callback will notify every drive removal. to see if it was last used drive call is_last_drive_removed() + void add_callback(std::function callback); // callback will notify only if device with last save path was removed void set_last_save_path(const std::string &path); bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() From 118354ecf43e366f6670b0dc6c83f6882f02b472 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 6 Dec 2019 13:21:44 +0100 Subject: [PATCH 024/162] erase callbacks --- src/slic3r/GUI/RemovableDriveManager.cpp | 4 ++++ src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 6581d53614..1fbc33fc57 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -494,6 +494,10 @@ void RemovableDriveManager::add_callback(std::function callback) { m_callbacks.push_back(callback); } +void RemovableDriveManager::erase_callbacks() +{ + m_callbacks.clear(); +} void RemovableDriveManager::set_last_save_path(const std::string& path) { std::string last_drive = get_drive_from_path(path); diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 741b4424ab..8d9e65c47e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -31,6 +31,7 @@ public: std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); void add_callback(std::function callback); // callback will notify only if device with last save path was removed + void erase_callbacks(); // erases all callbacks added by add_callback() void set_last_save_path(const std::string &path); bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() From 87fff4626e4a584abffb98da52dd62577cd997ee Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 6 Dec 2019 16:51:04 +0100 Subject: [PATCH 025/162] windows registration for device notif(thru hidden app) - windows doesnt need update now --- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/RemovableDriveManager.cpp | 108 ++++++++--------------- src/slic3r/GUI/RemovableDriveManager.hpp | 2 + 3 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index ed5371e669..90e6cd4bdb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -271,7 +271,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime()); + //RemovableDriveManager::get_instance().update(wxGetLocalTime()); // Preset updating & Configwizard are done after the above initializations, @@ -301,6 +301,7 @@ bool GUI_App::on_init_inner() preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); }); + RemovableDriveManager::get_instance().init(); } }); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 1fbc33fc57..5daa9eb261 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -8,9 +8,9 @@ #include #include -//#include -//GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, -// 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; +#include +GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, + 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; #else //linux includes @@ -29,7 +29,7 @@ namespace GUI { #if _WIN32 -//INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); @@ -136,13 +136,8 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) } void RemovableDriveManager::register_window() { - /* std::cout << "Registering for device notification\n"; - - - WNDCLASSEX wndClass; - wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); @@ -155,34 +150,41 @@ void RemovableDriveManager::register_window() wndClass.lpszClassName = L"PrusaSlicer_aux_class"; wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; - - HINSTANCE hInstanceExe = GetModuleHandle(NULL); + if(!RegisterClassEx(&wndClass)) + { + DWORD err = GetLastError(); + return; + } HWND hWnd = CreateWindowEx( - WS_EX_CLIENTEDGE | WS_EX_APPWINDOW, + WS_EX_NOACTIVATE, L"PrusaSlicer_aux_class", L"PrusaSlicer_aux_wnd", - WS_OVERLAPPEDWINDOW, // style + WS_DISABLED, // style CW_USEDEFAULT, 0, 640, 480, NULL, NULL, - hInstanceExe, + GetModuleHandle(NULL), NULL); -*/ + if(hWnd == NULL) + { + DWORD err = GetLastError(); + } + //ShowWindow(hWnd, SW_SHOWNORMAL); + UpdateWindow(hWnd); } -/* + INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT lRet = 1; static HDEVNOTIFY hDeviceNotify; + static HWND hEditWnd; static ULONGLONG msgCount = 0; switch (message) { case WM_CREATE: - - DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); @@ -196,55 +198,13 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle ); break; - - - case WM_DEVICECHANGE: { - std::cout << "WM_DEVICECHANGE\n"; - /* - // This is the actual message from the interface via Windows messaging. - // This code includes some additional decoding for this particular device type - // and some common validation checks. - // - // Note that not all devices utilize these optional parameters in the same - // way. Refer to the extended information for your particular device type - // specified by your GUID. - // - PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; - TCHAR strBuff[256]; - - // Output some messages to the window. - switch (wParam) + if(wParam == DBT_DEVICEREMOVECOMPLETE) { - case DBT_DEVICEARRIVAL: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount); - break; - case DBT_DEVICEREMOVECOMPLETE: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount); - break; - case DBT_DEVNODES_CHANGED: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount); - break; - default: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"), - msgCount, wParam); - break; + std::cout << "WM_DEVICECHANGE\n"; + RemovableDriveManager::get_instance().on_drive_removed_callback(); } - OutputMessage(hEditWnd, wParam, (LPARAM)strBuff); - / } break; default: @@ -254,7 +214,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP } return lRet; } -*/ + #else void RemovableDriveManager::search_for_drives() { @@ -420,15 +380,16 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) return ""; } #endif +void RemovableDriveManager::init() +{ + add_callback([](void) { RemovableDriveManager::get_instance().print(); }); +#if _WIN32 + register_window(); +#endif + update(); +} bool RemovableDriveManager::update(const long time) { - if(m_last_update == 0) - { - add_callback([](void) { RemovableDriveManager::get_instance().print(); }); -#if _WIN32 - //register_window(); -#endif - } if(time != 0) //time = 0 is forced update { long diff = m_last_update - time; @@ -442,7 +403,6 @@ bool RemovableDriveManager::update(const long time) } search_for_drives(); check_and_notify(); - //eject_drive(m_current_drives.back().path); return !m_current_drives.empty(); } @@ -523,6 +483,10 @@ void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } +void RemovableDriveManager::on_drive_removed_callback() +{ + update(); +} void RemovableDriveManager::print() { //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 8d9e65c47e..210d89477b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,6 +24,7 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. + void init(); bool update(const long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); @@ -36,6 +37,7 @@ public: bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); + void on_drive_removed_callback(); void print(); private: RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} From 0d2a2d2b20e128b6de3ca65b7140a26badeb23ba Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 9 Dec 2019 15:33:10 +0100 Subject: [PATCH 026/162] osx device unmount callback - not sure if will build --- src/slic3r/CMakeLists.txt | 1 + src/slic3r/GUI/RemovableDriveManager.cpp | 11 ++--- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +- src/slic3r/GUI/RemovableDriveManager.mm | 51 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/slic3r/GUI/RemovableDriveManager.mm diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 03413f9337..6a14a1b3f3 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -169,6 +169,7 @@ if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm Utils/MacDarkMode.mm + GUI/RemovableDriveManager.mm ) endif () diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 5daa9eb261..166728e68b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -203,7 +203,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP if(wParam == DBT_DEVICEREMOVECOMPLETE) { std::cout << "WM_DEVICECHANGE\n"; - RemovableDriveManager::get_instance().on_drive_removed_callback(); + RemovableDriveManager::get_instance().update(); } } break; @@ -219,6 +219,10 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP void RemovableDriveManager::search_for_drives() { +#if __APPLE__ + list_devices(); +#endif + m_current_drives.clear(); m_current_drives.reserve(26); @@ -483,10 +487,7 @@ void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } -void RemovableDriveManager::on_drive_removed_callback() -{ - update(); -} + void RemovableDriveManager::print() { //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 210d89477b..501c16b71a 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -37,7 +37,6 @@ public: bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); - void on_drive_removed_callback(); void print(); private: RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} @@ -52,6 +51,9 @@ private: #if _WIN32 void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +#elif __APPLE__ + void register_window(); + void list_devices(); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); diff --git a/src/slic3r/GUI/RemovableDriveManager.mm b/src/slic3r/GUI/RemovableDriveManager.mm new file mode 100644 index 0000000000..a1358625fc --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.mm @@ -0,0 +1,51 @@ +#import "RemovableDriveManager.hpp" + +@implementation RemovableDriveManager + +namespace Slic3r { +namespace GUI { + +void RemovableDriveManager::register_window() +{ + //[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumesChanged:) name:NSWorkspaceDidMountNotification object: nil]; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; +} + +-(void) on_device_unmount: (NSNotification*) notification +{ + NSLog(@"on device change"); + RemovableDriveManager::get_instance().update(); +} + +-(void) RemovableDriveManager::list_devices() +{ + NSLog(@"---"); + NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; + for (NSString* volumePath in listOfMedia) + { + NSLog(@"@", volumePath); + } + NSLog(@"--"); + //removable here means CD not USB :/ + NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; + NSLog(@"%@", listOfMedia); + + for (NSString* volumePath in listOfMedia) + { + BOOL isRemovable = NO; + BOOL isWritable = NO; + BOOL isUnmountable = NO; + NSString* description = [NSString string]; + NSString* type = [NSString string]; + + BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath + isRemovable:&isRemovable + isWritable:&isWritable + isUnmountable:&isUnmountable + description:&description + type:&type]; + NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); + } +} + +}}//namespace Slicer::GUI \ No newline at end of file From 8810a9aa31d07a63a1de6af0fefeb6ed6cb1f183 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 9 Dec 2019 17:12:22 +0100 Subject: [PATCH 027/162] init call --- src/slic3r/GUI/GUI_App.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 90e6cd4bdb..1b2fe919a2 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -260,6 +260,8 @@ bool GUI_App::on_init_inner() m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); + RemovableDriveManager::get_instance().init(); + Bind(wxEVT_IDLE, [this](wxIdleEvent& event) { if (! plater_) @@ -301,7 +303,7 @@ bool GUI_App::on_init_inner() preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); }); - RemovableDriveManager::get_instance().init(); + } }); From fdc493f6fd1d76209e5109f55d47aa9619867597 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 10 Dec 2019 10:08:57 +0100 Subject: [PATCH 028/162] macos mm files --- src/slic3r/CMakeLists.txt | 3 +- src/slic3r/GUI/RemovableDriveManager.hpp | 3 +- src/slic3r/GUI/RemovableDriveManagerMM.h | 9 ++++++ ...eManager.mm => RemovableDriveManagerMM.mm} | 29 +++++++++++++++---- 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 src/slic3r/GUI/RemovableDriveManagerMM.h rename src/slic3r/GUI/{RemovableDriveManager.mm => RemovableDriveManagerMM.mm} (86%) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 6a14a1b3f3..9d51f6219c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -169,7 +169,8 @@ if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm Utils/MacDarkMode.mm - GUI/RemovableDriveManager.mm + GUI/RemovableDriveManagerMM.mm + GUI/RemovableDriveManagerMM.h ) endif () diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 501c16b71a..04bbe48b5d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -52,8 +52,9 @@ private: void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #elif __APPLE__ + void *m_rdmmm; void register_window(); - void list_devices(); + //void list_devices(); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h new file mode 100644 index 0000000000..8f783c2d2a --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -0,0 +1,9 @@ +#import + +@interface RemovableDriveManagerMM : NSObject + +-(instancetype) init; +-(void) add_unmount_observer; +-(void) on_device_unmount: (NSNotification*) notification; + +@end \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm similarity index 86% rename from src/slic3r/GUI/RemovableDriveManager.mm rename to src/slic3r/GUI/RemovableDriveManagerMM.mm index a1358625fc..e4e324654e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -1,22 +1,39 @@ #import "RemovableDriveManager.hpp" -@implementation RemovableDriveManager +#import + +@implementation RemovableDriveManagerMM namespace Slic3r { namespace GUI { -void RemovableDriveManager::register_window() +-(instancetype) init { - //[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumesChanged:) name:NSWorkspaceDidMountNotification object: nil]; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; + self = [super init]; + if(self) + { + [self add_unmount_observer] + } + return self; } - -(void) on_device_unmount: (NSNotification*) notification { NSLog(@"on device change"); RemovableDriveManager::get_instance().update(); } +-(void) add_unmount_observer +{ + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; +} +void RemovableDriveManager::register_window() +{ + m_rdmmm = nullptr; + m_rdmmm = [[RemovableDriveManagerMM alloc] init]; +} + + +/* -(void) RemovableDriveManager::list_devices() { NSLog(@"---"); @@ -47,5 +64,5 @@ void RemovableDriveManager::register_window() NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); } } - +*/ }}//namespace Slicer::GUI \ No newline at end of file From 40a83e67dd11f2cb66beae511159aa42c9a44fad Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Tue, 10 Dec 2019 11:17:12 +0100 Subject: [PATCH 029/162] macos implementation --- src/slic3r/GUI/RemovableDriveManager.cpp | 8 +++++--- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +++- src/slic3r/GUI/RemovableDriveManagerMM.mm | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 166728e68b..8145c90760 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -218,11 +218,11 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP #else void RemovableDriveManager::search_for_drives() { - + /* #if __APPLE__ list_devices(); #endif - +*/ m_current_drives.clear(); m_current_drives.reserve(26); @@ -389,6 +389,8 @@ void RemovableDriveManager::init() add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); +#elif __APPLE__ + register_window(); #endif update(); } @@ -493,4 +495,4 @@ void RemovableDriveManager::print() //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; std::cout << "notified\n"; } -}}//namespace Slicer::Gui:: \ No newline at end of file +}}//namespace Slicer::Gui:: diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 04bbe48b5d..c4f55029b7 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -55,10 +55,12 @@ private: void *m_rdmmm; void register_window(); //void list_devices(); + void search_path(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; }} -#endif \ No newline at end of file +#endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index e4e324654e..99abd73860 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -1,37 +1,38 @@ #import "RemovableDriveManager.hpp" - +#import "RemovableDriveManagerMM.h" #import @implementation RemovableDriveManagerMM -namespace Slic3r { -namespace GUI { + -(instancetype) init { self = [super init]; if(self) { - [self add_unmount_observer] + [self add_unmount_observer]; } return self; } -(void) on_device_unmount: (NSNotification*) notification { NSLog(@"on device change"); - RemovableDriveManager::get_instance().update(); + Slic3r::GUI::RemovableDriveManager::get_instance().update(); } -(void) add_unmount_observer { + NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; } - +namespace Slic3r { +namespace GUI { void RemovableDriveManager::register_window() { m_rdmmm = nullptr; m_rdmmm = [[RemovableDriveManagerMM alloc] init]; } - +}}//namespace Slicer::GUI /* -(void) RemovableDriveManager::list_devices() @@ -65,4 +66,5 @@ void RemovableDriveManager::register_window() } } */ -}}//namespace Slicer::GUI \ No newline at end of file + +@end From 3b6daf64c7b22a2ba3ffa7dda89bc22aa36fd0a1 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Tue, 10 Dec 2019 11:35:39 +0100 Subject: [PATCH 030/162] macos list devices --- src/slic3r/GUI/RemovableDriveManager.cpp | 4 +- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +- src/slic3r/GUI/RemovableDriveManagerMM.h | 4 +- src/slic3r/GUI/RemovableDriveManagerMM.mm | 65 +++++++++++++---------- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 8145c90760..50e2b6359c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -218,11 +218,11 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP #else void RemovableDriveManager::search_for_drives() { - /* + #if __APPLE__ list_devices(); #endif -*/ + m_current_drives.clear(); m_current_drives.reserve(26); diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c4f55029b7..7109bbd070 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -39,7 +39,7 @@ public: void reset_last_save_path(); void print(); private: - RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} + RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(nullptr){} void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" @@ -54,7 +54,7 @@ private: #elif __APPLE__ void *m_rdmmm; void register_window(); - //void list_devices(); + void list_devices(); void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #else diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h index 8f783c2d2a..4a5fa2515e 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.h +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -5,5 +5,5 @@ -(instancetype) init; -(void) add_unmount_observer; -(void) on_device_unmount: (NSNotification*) notification; - -@end \ No newline at end of file +-(void) list_dev; +@end diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 99abd73860..7e8b56c59b 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -25,6 +25,36 @@ NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; } +-(void) list_dev +{ + NSLog(@"---"); + NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; + for (NSString* volumePath in devices) + { + NSLog(@"@", volumePath); + } + NSLog(@"--"); + //removable here means CD not USB :/ + NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; + NSLog(@"%@", listOfMedia); + + for (NSString* volumePath in listOfMedia) + { + BOOL isRemovable = NO; + BOOL isWritable = NO; + BOOL isUnmountable = NO; + NSString* description = [NSString string]; + NSString* type = [NSString string]; + + BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath + isRemovable:&isRemovable + isWritable:&isWritable + isUnmountable:&isUnmountable + description:&description + type:&type]; + NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); + } +} namespace Slic3r { namespace GUI { void RemovableDriveManager::register_window() @@ -32,39 +62,16 @@ void RemovableDriveManager::register_window() m_rdmmm = nullptr; m_rdmmm = [[RemovableDriveManagerMM alloc] init]; } +void RemovableDriveManager::list_devices() +{ + if(m_rdmmm == nullptr) + return; + [m_rdmmm list_dev]; +} }}//namespace Slicer::GUI /* --(void) RemovableDriveManager::list_devices() -{ - NSLog(@"---"); - NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; - for (NSString* volumePath in listOfMedia) - { - NSLog(@"@", volumePath); - } - NSLog(@"--"); - //removable here means CD not USB :/ - NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; - NSLog(@"%@", listOfMedia); - for (NSString* volumePath in listOfMedia) - { - BOOL isRemovable = NO; - BOOL isWritable = NO; - BOOL isUnmountable = NO; - NSString* description = [NSString string]; - NSString* type = [NSString string]; - - BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath - isRemovable:&isRemovable - isWritable:&isWritable - isUnmountable:&isUnmountable - description:&description - type:&type]; - NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); - } -} */ @end From d2a440c79440b63cda1c62e8b2f423b2e616bde4 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 10 Dec 2019 14:10:47 +0100 Subject: [PATCH 031/162] macos better wrapper --- src/slic3r/GUI/RemovableDriveManager.cpp | 50 +++++++++-------- src/slic3r/GUI/RemovableDriveManager.hpp | 33 ++++++++--- src/slic3r/GUI/RemovableDriveManagerMM.h | 2 +- src/slic3r/GUI/RemovableDriveManagerMM.mm | 68 +++++++++++------------ 4 files changed, 87 insertions(+), 66 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 50e2b6359c..763113ea2c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -220,9 +220,11 @@ void RemovableDriveManager::search_for_drives() { #if __APPLE__ - list_devices(); -#endif - + if(m_rdmmm) + { + m_rdmmm->list_devices(); + } +#else m_current_drives.clear(); m_current_drives.reserve(26); @@ -273,6 +275,7 @@ void RemovableDriveManager::search_for_drives() } //std::cout << "found drives:" <pw_name == username) - { - std::string name = basename(globbuf.gl_pathv[i]); - m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); - } - } - } + } }else { @@ -310,7 +296,27 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin globfree(&globbuf); } - +void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path) +{ + //if not same file system - could be removable drive + if(!compare_filesystem_id(globbuf.gl_pathv[i], parent_path)) + { + //user id + struct stat buf; + stat(globbuf.gl_pathv[i],&buf); + uid_t uid = buf.st_uid; + std::string username(std::getenv("USER")); + struct passwd *pw = getpwuid(uid); + if(pw != 0) + { + if(pw->pw_name == username) + { + std::string name = basename(globbuf.gl_pathv[i]); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); + } + } + } +} bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, const std::string &path_b) { struct stat buf; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 7109bbd070..202680328e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -39,7 +39,11 @@ public: void reset_last_save_path(); void print(); private: - RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(nullptr){} +#if __APPLE__ + RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(new RemovableDriveManagerMM()){} +#else + RemovableDriveManager() : m_drives_count(0), m_last_update(0), m_last_save_path(""){} +#endif void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" @@ -51,16 +55,27 @@ private: #if _WIN32 void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -#elif __APPLE__ - void *m_rdmmm; - void register_window(); - void list_devices(); - void search_path(const std::string &path, const std::string &parent_path); - bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #else - void search_path(const std::string &path, const std::string &parent_path); - bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); +#if __APPLE__ + RemovableDriveManagerMM * m_rdmmm; + #endif + void search_path(const std::string &path, const std::string &parent_path); + void inspect_file(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; +#if __APPLE__ +class RemovableDriveManagerMM +{ +public: + RemovableDriveManagerMM(); + ~RemovableDriveManagerMM(); + register_window(); + list_devices(); +private: + RemovableDriveManagerMMImpl *m_imp; + friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); +}; +#endif }} #endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h index 4a5fa2515e..2999415454 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.h +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -5,5 +5,5 @@ -(instancetype) init; -(void) add_unmount_observer; -(void) on_device_unmount: (NSNotification*) notification; --(void) list_dev; +-(NSArray*) list_dev; @end diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 7e8b56c59b..25fa6da091 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -10,8 +10,7 @@ { self = [super init]; if(self) - { - [self add_unmount_observer]; + { } return self; } @@ -25,48 +24,49 @@ NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; } --(void) list_dev +-(NSArray*) list_dev { - NSLog(@"---"); NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; for (NSString* volumePath in devices) { - NSLog(@"@", volumePath); - } - NSLog(@"--"); - //removable here means CD not USB :/ - NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; - NSLog(@"%@", listOfMedia); + NSLog(@"%@", volumePath); + } + return devices; - for (NSString* volumePath in listOfMedia) - { - BOOL isRemovable = NO; - BOOL isWritable = NO; - BOOL isUnmountable = NO; - NSString* description = [NSString string]; - NSString* type = [NSString string]; - - BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath - isRemovable:&isRemovable - isWritable:&isWritable - isUnmountable:&isUnmountable - description:&description - type:&type]; - NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); - } } namespace Slic3r { namespace GUI { -void RemovableDriveManager::register_window() -{ - m_rdmmm = nullptr; - m_rdmmm = [[RemovableDriveManagerMM alloc] init]; +struct RemovableDriveManagerMMImpl{ + RemovableDriveManagerMM * wrap; } -void RemovableDriveManager::list_devices() +RemovableDriveManagerMM():impl(new RemovableDriveManagerMMImpl){ + impl->wrap = [[RemovableDriveManagerMM alloc] init]; +} +RemovableDriveManagerMM::~RemovableDriveManagerMM() { - if(m_rdmmm == nullptr) - return; - [m_rdmmm list_dev]; + if(impl) + { + [impl->wrap release]; + } +} +void RDMMMWrapper::register_window() +{ + if(impl->wrap) + { + [impl->wrap add_unmount_observer]; + } +} +void RDMMMWrapper::list_devices() +{ + if(impl->wrap) + { + NSArray* devices = [impl->wrap list_dev]; + for (NSString* volumePath in devices) + { + NSLog(@"%@", volumePath); + Slic3r::GUI::RemovableDriveManager::get_instance().inspect_file(std::string([volumePath UTF8String]), "/Volumes"); + } + } } }}//namespace Slicer::GUI From 027b9f508285b3ab7e9783f4c165aa99bee4f886 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 10 Dec 2019 14:41:49 +0100 Subject: [PATCH 032/162] fix --- src/slic3r/GUI/RemovableDriveManager.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 763113ea2c..c5dca1bd55 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -231,9 +231,10 @@ void RemovableDriveManager::search_for_drives() //search /media/* folder search_path("/media/*", "/media"); +/* //search /Volumes/* folder (OSX) search_path("/Volumes/*", "/Volumes"); - +*/ std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; @@ -286,7 +287,7 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin { for(size_t i = 0; i < globbuf.gl_pathc; i++) { - + inspect_file(globbuf.gl_pathv[i], parent_path); } }else { @@ -299,11 +300,11 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path) { //if not same file system - could be removable drive - if(!compare_filesystem_id(globbuf.gl_pathv[i], parent_path)) + if(!compare_filesystem_id(path, parent_path)) { //user id struct stat buf; - stat(globbuf.gl_pathv[i],&buf); + stat(path.c_str(), &buf); uid_t uid = buf.st_uid; std::string username(std::getenv("USER")); struct passwd *pw = getpwuid(uid); @@ -311,8 +312,8 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str { if(pw->pw_name == username) { - std::string name = basename(globbuf.gl_pathv[i]); - m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); + std::string name = basename(const_cast(path.c_str())); + m_current_drives.push_back(DriveData(name,path)); } } } From 37b6d9e8adb5964d7933bcc999302a0a1301f6b7 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 10 Dec 2019 17:31:27 +0100 Subject: [PATCH 033/162] Implemented "Disconnect" button --- src/slic3r/GUI/Plater.cpp | 41 ++++++++++++++++++++++++++++++++------- src/slic3r/GUI/Plater.hpp | 1 + 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d1ce50f41f..b50f6f150d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -700,6 +700,7 @@ struct Sidebar::priv wxButton *btn_export_gcode; wxButton *btn_reslice; wxButton *btn_send_gcode; + ScalableButton *btn_disconnect; priv(Plater *plater) : plater(plater) {} ~priv(); @@ -848,22 +849,39 @@ Sidebar::Sidebar(Plater *parent) // Buttons underneath the scrolled area - auto init_btn = [this](wxButton **btn, wxString label) { + auto init_btn = [this](wxButton **btn, wxString label, const std::string icon_name = "", wxString tooltip = wxEmptyString) { *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); (*btn)->SetFont(wxGetApp().bold_font()); + (*btn)->SetToolTip(tooltip); + + if (!icon_name.empty()) + (*btn)->SetBitmap(create_scaled_bitmap(this, icon_name)); }; - init_btn(&p->btn_send_gcode, _(L("Send to printer"))); + init_btn(&p->btn_send_gcode, /*_(L("Send to printer"))*/"", "export_gcode", _(L("Send to printer"))); p->btn_send_gcode->Hide(); init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots); init_btn(&p->btn_reslice, _(L("Slice now"))); + + p->btn_disconnect = new ScalableButton(this, wxID_ANY, "revert_all_", "", + wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT); + p->btn_disconnect->Hide(); + p->btn_disconnect->SetToolTip(_(L("Remove device"))); + enable_buttons(false); auto *btns_sizer = new wxBoxSizer(wxVERTICAL); + + auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); + complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); + complect_btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND); + complect_btns_sizer->Add(p->btn_disconnect); + btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); - btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); - btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); + btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5); +// btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); +// btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(p->scrolled, 1, wxEXPAND); @@ -882,6 +900,9 @@ Sidebar::Sidebar(Plater *parent) p->plater->select_view_3D("Preview"); }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); + p->btn_disconnect->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { + // #dk_FIXME + }); } Sidebar::~Sidebar() {} @@ -1255,11 +1276,13 @@ void Sidebar::enable_buttons(bool enable) p->btn_reslice->Enable(enable); p->btn_export_gcode->Enable(enable); p->btn_send_gcode->Enable(enable); + p->btn_disconnect->Enable(enable); } bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); } bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); } bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); } +bool Sidebar::show_disconnect(bool show)const { return p->btn_disconnect->Show(show); } bool Sidebar::is_multifilament() { @@ -4019,20 +4042,24 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const wxWindowUpdateLocker noUpdater(sidebar); const auto prin_host_opt = config->option("print_host"); const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); + + const bool disconnect_shown = true; // #dk_FIXME // when a background processing is ON, export_btn and/or send_btn are showing if (wxGetApp().app_config->get("background_processing") == "1") { if (sidebar->show_reslice(false) | sidebar->show_export(true) | - sidebar->show_send(send_gcode_shown)) + sidebar->show_send(send_gcode_shown) | + sidebar->show_disconnect(disconnect_shown)) sidebar->Layout(); } else { if (sidebar->show_reslice(is_ready_to_slice) | sidebar->show_export(!is_ready_to_slice) | - sidebar->show_send(send_gcode_shown && !is_ready_to_slice)) + sidebar->show_send(send_gcode_shown && !is_ready_to_slice) | + sidebar->show_disconnect(disconnect_shown && !is_ready_to_slice)) sidebar->Layout(); } } @@ -4273,7 +4300,7 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab { case ActionButtonType::abReslice: p->btn_reslice->SetLabelText(label); break; case ActionButtonType::abExport: p->btn_export_gcode->SetLabelText(label); break; - case ActionButtonType::abSendGCode: p->btn_send_gcode->SetLabelText(label); break; + case ActionButtonType::abSendGCode: /*p->btn_send_gcode->SetLabelText(label);*/ break; } } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 5c36dbf5e0..af4b989c42 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -119,6 +119,7 @@ public: bool show_reslice(bool show) const; bool show_export(bool show) const; bool show_send(bool show) const; + bool show_disconnect(bool show)const; bool is_multifilament(); void update_mode(); From cd1d49b015e7f90c375c44bc6ef15e11507dfdaf Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 10:16:32 +0100 Subject: [PATCH 034/162] macos better wrapper --- src/slic3r/GUI/RemovableDriveManager.hpp | 29 +++++++++++++---------- src/slic3r/GUI/RemovableDriveManagerMM.mm | 21 +++++++--------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 202680328e..cbf6f53aac 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -6,6 +6,10 @@ namespace Slic3r { namespace GUI { +class RDMMMWrapper; +#if __APPLE__ + + struct DriveData { std::string name; @@ -57,25 +61,24 @@ private: //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #else #if __APPLE__ - RemovableDriveManagerMM * m_rdmmm; + RDMMMWrapper * m_rdmmm; #endif void search_path(const std::string &path, const std::string &parent_path); void inspect_file(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; -#if __APPLE__ -class RemovableDriveManagerMM -{ -public: - RemovableDriveManagerMM(); - ~RemovableDriveManagerMM(); - register_window(); - list_devices(); -private: - RemovableDriveManagerMMImpl *m_imp; - friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); -}; + class RDMMMWrapper + { + public: + RDMMMWrapper(); + ~RDMMMWrapper(); + void register_window(); + void list_devices(); + private: + void *m_imp; + friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); + }; #endif }} #endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 25fa6da091..269a2255b0 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -36,31 +36,28 @@ } namespace Slic3r { namespace GUI { -struct RemovableDriveManagerMMImpl{ - RemovableDriveManagerMM * wrap; +RDMMMWrapper::RDMMMWrapper():m_imp(nullptr){ + m_imp = [[RemovableDriveManagerMM alloc] init]; } -RemovableDriveManagerMM():impl(new RemovableDriveManagerMMImpl){ - impl->wrap = [[RemovableDriveManagerMM alloc] init]; -} -RemovableDriveManagerMM::~RemovableDriveManagerMM() +RDMMMWrapper::~RDMMMWrapper() { - if(impl) + if(m_imp) { - [impl->wrap release]; + [m_imp release]; } } void RDMMMWrapper::register_window() { - if(impl->wrap) + if(m_imp) { - [impl->wrap add_unmount_observer]; + [m_imp add_unmount_observer]; } } void RDMMMWrapper::list_devices() { - if(impl->wrap) + if(m_imp) { - NSArray* devices = [impl->wrap list_dev]; + NSArray* devices = [m_imp list_dev]; for (NSString* volumePath in devices) { NSLog(@"%@", volumePath); From be09c91a1d1984e74d4ec0133314200fe100b1cf Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 11 Dec 2019 11:00:23 +0100 Subject: [PATCH 035/162] Added missed icon --- resources/icons/revert_all_.svg | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 resources/icons/revert_all_.svg diff --git a/resources/icons/revert_all_.svg b/resources/icons/revert_all_.svg new file mode 100644 index 0000000000..fe8de635db --- /dev/null +++ b/resources/icons/revert_all_.svg @@ -0,0 +1,9 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + + + \ No newline at end of file From bcfc333fb108f87e62f961f403ede08cebc124a5 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 11:00:47 +0100 Subject: [PATCH 036/162] macos better wrapper --- src/slic3r/GUI/RemovableDriveManager.cpp | 12 ++++++- src/slic3r/GUI/RemovableDriveManager.hpp | 40 ++++++++++++----------- src/slic3r/GUI/RemovableDriveManagerMM.mm | 4 --- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index c5dca1bd55..164b6e38aa 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -391,13 +391,23 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) return ""; } #endif + +RemovableDriveManager::RemovableDriveManager(): + m_drives_count(0), + m_last_update(0), + m_last_save_path(""), +#if __APPLE__ + m_rdmmm(new RDMMMWrapper()) +#endif +{} + void RemovableDriveManager::init() { add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); #elif __APPLE__ - register_window(); + m_rdmmm->register_window(); #endif update(); } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index cbf6f53aac..a5027a5adf 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -6,9 +6,9 @@ namespace Slic3r { namespace GUI { -class RDMMMWrapper; #if __APPLE__ - +class RDMMMWrapper; +#endif struct DriveData { @@ -18,6 +18,9 @@ struct DriveData }; class RemovableDriveManager { +#if __APPLE__ +friend class RDMMMWrapper; +#endif public: static RemovableDriveManager& get_instance() { @@ -42,12 +45,9 @@ public: bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); void print(); + private: -#if __APPLE__ - RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(new RemovableDriveManagerMM()){} -#else - RemovableDriveManager() : m_drives_count(0), m_last_update(0), m_last_save_path(""){} -#endif + RemovableDriveManager(); void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" @@ -64,21 +64,23 @@ private: RDMMMWrapper * m_rdmmm; #endif void search_path(const std::string &path, const std::string &parent_path); - void inspect_file(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); + void inspect_file(const std::string &path, const std::string &parent_path); #endif }; - class RDMMMWrapper - { - public: - RDMMMWrapper(); - ~RDMMMWrapper(); - void register_window(); - void list_devices(); - private: - void *m_imp; - friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); - }; + +#if __APPLE__ +class RDMMMWrapper +{ +public: + RDMMMWrapper(); + ~RDMMMWrapper(); + void register_window(); + void list_devices(); +protected: + void *m_imp; + //friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); +}; #endif }} #endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 269a2255b0..d32b7b278e 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -27,10 +27,6 @@ -(NSArray*) list_dev { NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; - for (NSString* volumePath in devices) - { - NSLog(@"%@", volumePath); - } return devices; } From 975642e3e055297bd178196c16a69eaf58cb75bb Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 12:28:51 +0100 Subject: [PATCH 037/162] eject button functionality --- src/slic3r/GUI/Plater.cpp | 19 ++++++++++++++++++- src/slic3r/GUI/Plater.hpp | 2 ++ src/slic3r/GUI/RemovableDriveManager.cpp | 22 +++++++++------------- src/slic3r/GUI/RemovableDriveManager.hpp | 8 +++++--- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b50f6f150d..e94e0a4e63 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -902,6 +902,7 @@ Sidebar::Sidebar(Plater *parent) p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); p->btn_disconnect->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { // #dk_FIXME + p->plater->eject_drive(); }); } @@ -4043,7 +4044,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const const auto prin_host_opt = config->option("print_host"); const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); - const bool disconnect_shown = true; // #dk_FIXME + const bool disconnect_shown = !(RemovableDriveManager::get_instance().is_last_drive_removed()); // #dk_FIXME // when a background processing is ON, export_btn and/or send_btn are showing if (wxGetApp().app_config->get("background_processing") == "1") @@ -4886,6 +4887,22 @@ void Plater::send_gcode() } } +void Plater::eject_drive() +{ + if (GUI::RemovableDriveManager::get_instance().update()) + { + RemovableDriveManager::get_instance().erase_callbacks(); + RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); + RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_drive_path()); + } +} +void Plater::drive_ejected_callback() +{ + p->show_action_buttons(false); +} + + + void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); } void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); } void Plater::suppress_snapshots() { p->suppress_snapshots(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index af4b989c42..a247f82922 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -202,6 +202,8 @@ public: void suppress_background_process(const bool stop_background_process) ; void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); void send_gcode(); + void eject_drive(); + void drive_ejected_callback(); void take_snapshot(const std::string &snapshot_name); void take_snapshot(const wxString &snapshot_name); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 164b6e38aa..1a964f889d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -395,9 +395,9 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) RemovableDriveManager::RemovableDriveManager(): m_drives_count(0), m_last_update(0), - m_last_save_path(""), + m_last_save_path("") #if __APPLE__ - m_rdmmm(new RDMMMWrapper()) + , m_rdmmm(new RDMMMWrapper()) #endif {} @@ -411,7 +411,7 @@ void RemovableDriveManager::init() #endif update(); } -bool RemovableDriveManager::update(const long time) +bool RemovableDriveManager::update(const long time, bool check) { if(time != 0) //time = 0 is forced update { @@ -425,7 +425,7 @@ bool RemovableDriveManager::update(const long time) } } search_for_drives(); - check_and_notify(); + if(check)check_and_notify(); return !m_current_drives.empty(); } @@ -444,13 +444,7 @@ bool RemovableDriveManager::is_drive_mounted(const std::string &path) std::string RemovableDriveManager::get_last_drive_path() { - if (!m_current_drives.empty()) - { - if (m_last_save_path != "") - return m_last_save_path; - return m_current_drives.back().path; - } - return ""; + return m_last_save_path; } std::vector RemovableDriveManager::get_all_drives() { @@ -495,11 +489,13 @@ bool RemovableDriveManager::is_last_drive_removed() { return true; } - return !is_drive_mounted(m_last_save_path); + bool r = !is_drive_mounted(m_last_save_path); + if (r) reset_last_save_path(); + return r; } bool RemovableDriveManager::is_last_drive_removed_with_update(const long time) { - update(time); + update(time, false); return is_last_drive_removed(); } void RemovableDriveManager::reset_last_save_path() diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index a5027a5adf..f412940010 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -32,7 +32,7 @@ public: //update() searches for removable devices, returns false if empty. void init(); - bool update(const long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0, bool check = true); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_drive_path(); @@ -41,9 +41,8 @@ public: void add_callback(std::function callback); // callback will notify only if device with last save path was removed void erase_callbacks(); // erases all callbacks added by add_callback() void set_last_save_path(const std::string &path); - bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); + bool is_last_drive_removed(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() - void reset_last_save_path(); void print(); private: @@ -51,11 +50,14 @@ private: void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" + void reset_last_save_path(); + std::vector m_current_drives; std::vector> m_callbacks; size_t m_drives_count; long m_last_update; std::string m_last_save_path; + #if _WIN32 void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); From 4a7f50ad669a3b71cf152b61a751cc088151578e Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 14:53:28 +0100 Subject: [PATCH 038/162] eject button functionality --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 +++--- src/slic3r/GUI/RemovableDriveManager.cpp | 24 +++++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.hpp | 5 +++-- src/slic3r/GUI/RemovableDriveManagerMM.mm | 2 +- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1b2fe919a2..fc25b4f295 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -273,7 +273,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - //RemovableDriveManager::get_instance().update(wxGetLocalTime()); + RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e94e0a4e63..905d56e900 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4588,7 +4588,7 @@ void Plater::export_gcode() { if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) { - start_dir = RemovableDriveManager::get_instance().get_last_drive_path(); + start_dir = RemovableDriveManager::get_instance().get_drive_path(); } } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), @@ -4889,11 +4889,11 @@ void Plater::send_gcode() void Plater::eject_drive() { - if (GUI::RemovableDriveManager::get_instance().update()) + if (GUI::RemovableDriveManager::get_instance().update(0, true)) { RemovableDriveManager::get_instance().erase_callbacks(); RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); - RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_drive_path()); + RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); } } void Plater::drive_ejected_callback() diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 1a964f889d..49bf59e11f 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -198,15 +198,16 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle ); break; + /* case WM_DEVICECHANGE: { if(wParam == DBT_DEVICEREMOVECOMPLETE) { - std::cout << "WM_DEVICECHANGE\n"; - RemovableDriveManager::get_instance().update(); +- RemovableDriveManager::get_instance().update(0, true); } } break; + */ default: // Send all other messages on to the default windows handler. lRet = DefWindowProc(hWnd, message, wParam, lParam); @@ -403,7 +404,7 @@ RemovableDriveManager::RemovableDriveManager(): void RemovableDriveManager::init() { - add_callback([](void) { RemovableDriveManager::get_instance().print(); }); + //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); #elif __APPLE__ @@ -441,8 +442,18 @@ bool RemovableDriveManager::is_drive_mounted(const std::string &path) } return false; } - -std::string RemovableDriveManager::get_last_drive_path() +std::string RemovableDriveManager::get_drive_path() +{ + if (m_current_drives.size() == 0) + { + reset_last_save_path(); + return ""; + } + if (m_last_save_path != "") + return m_last_save_path; + return m_current_drives.back().path; +} +std::string RemovableDriveManager::get_last_save_path() { return m_last_save_path; } @@ -456,7 +467,7 @@ void RemovableDriveManager::check_and_notify() if(m_drives_count != m_current_drives.size()) { //std::cout<<" vs "<< m_current_drives.size(); - if(m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) + if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { @@ -485,6 +496,7 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) } bool RemovableDriveManager::is_last_drive_removed() { + m_drives_count = m_current_drives.size(); if(m_last_save_path == "") { return true; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index f412940010..49df414827 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -32,10 +32,11 @@ public: //update() searches for removable devices, returns false if empty. void init(); - bool update(const long time = 0, bool check = true); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0, bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); - std::string get_last_drive_path(); + std::string get_last_save_path(); + std::string get_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); void add_callback(std::function callback); // callback will notify only if device with last save path was removed diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index d32b7b278e..7a1108541a 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -17,7 +17,7 @@ -(void) on_device_unmount: (NSNotification*) notification { NSLog(@"on device change"); - Slic3r::GUI::RemovableDriveManager::get_instance().update(); + Slic3r::GUI::RemovableDriveManager::get_instance().update(0,true); } -(void) add_unmount_observer { From 6dddc1cc6bcb1b7376b2af15bd271f2984190377 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 15:02:20 +0100 Subject: [PATCH 039/162] eject button functionality --- src/slic3r/GUI/Plater.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 905d56e900..0300670e48 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4603,7 +4603,9 @@ void Plater::export_gcode() fs::path path = into_path(dlg.GetPath()); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = std::move(path); - RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); + } if (! output_path.empty()) p->export_gcode(std::move(output_path), PrintHostJob()); From 38c69f16f04cd051d66175e39514c4e0873de8e5 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 16:59:26 +0100 Subject: [PATCH 040/162] macos eject --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.cpp | 5 +++++ src/slic3r/GUI/RemovableDriveManager.hpp | 1 + src/slic3r/GUI/RemovableDriveManagerMM.mm | 4 ++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fc25b4f295..8e450f4972 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -273,7 +273,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); + //RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 49bf59e11f..284c224fbd 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -425,6 +425,10 @@ bool RemovableDriveManager::update(const long time, bool check) return false; // return value shouldnt matter if update didnt run } } + if(check) + { + m_rdmmm->log("update"); + } search_for_drives(); if(check)check_and_notify(); return !m_current_drives.empty(); @@ -466,6 +470,7 @@ void RemovableDriveManager::check_and_notify() //std::cout<<"drives count: "<log("drives count not same"); //std::cout<<" vs "<< m_current_drives.size(); if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 49df414827..9eea355f79 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -80,6 +80,7 @@ public: ~RDMMMWrapper(); void register_window(); void list_devices(); + void log(const std::string &msg); protected: void *m_imp; //friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 7a1108541a..45bd21bcfa 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -61,6 +61,10 @@ void RDMMMWrapper::list_devices() } } } +void RDMMMWrapper::log(const std::string &msg) +{ + NSLog(@"%s", msg.c_str()); +} }}//namespace Slicer::GUI /* From f057077826b7499a54f7b21ef198a370446b53ad Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 17:02:12 +0100 Subject: [PATCH 041/162] eject button functionality --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fc25b4f295..8e450f4972 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -273,7 +273,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); + //RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 49bf59e11f..dc8469d9a2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -96,14 +96,16 @@ void RemovableDriveManager::eject_drive(const std::string &path) return; } DWORD deviceControlRetVal(0); + DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); - CloseHandle(handle); if (error == 0) { + CloseHandle(handle); std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; return; } - + CloseHandle(handle); m_current_drives.erase(it); break; @@ -198,7 +200,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle ); break; - /* + case WM_DEVICECHANGE: { if(wParam == DBT_DEVICEREMOVECOMPLETE) @@ -207,7 +209,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP } } break; - */ + default: // Send all other messages on to the default windows handler. lRet = DefWindowProc(hWnd, message, wParam, lParam); From a03ce255d6ad5b84b62f1bb9afa5b34e3e13617b Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 17:39:34 +0100 Subject: [PATCH 042/162] macos eject --- src/slic3r/GUI/RemovableDriveManager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index afe5ee7393..ab2dd10eb2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -221,15 +221,17 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP #else void RemovableDriveManager::search_for_drives() { - + + m_current_drives.clear(); + m_current_drives.reserve(26); + #if __APPLE__ if(m_rdmmm) { m_rdmmm->list_devices(); } #else - m_current_drives.clear(); - m_current_drives.reserve(26); + //search /media/* folder search_path("/media/*", "/media"); From e2048775f6bc1f729df39843d7683ad33f457c1b Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 17:42:56 +0100 Subject: [PATCH 043/162] eject button functionality --- src/slic3r/GUI/Plater.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0300670e48..a0e453abc3 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4891,12 +4891,11 @@ void Plater::send_gcode() void Plater::eject_drive() { - if (GUI::RemovableDriveManager::get_instance().update(0, true)) - { - RemovableDriveManager::get_instance().erase_callbacks(); - RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); - RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); - } + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().erase_callbacks(); + RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); + RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); + } void Plater::drive_ejected_callback() { From 59fa78373b1a0cd199bfac3ddc513235ca33e59f Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 18:30:03 +0100 Subject: [PATCH 044/162] linux eject --- src/slic3r/GUI/GUI_App.cpp | 6 +++--- src/slic3r/GUI/RemovableDriveManager.cpp | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 8e450f4972..258e338719 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -272,9 +272,9 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - - //RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); - +#if __linux__ + RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); +#endif // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ab2dd10eb2..d5f2244095 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -429,10 +429,6 @@ bool RemovableDriveManager::update(const long time, bool check) return false; // return value shouldnt matter if update didnt run } } - if(check) - { - m_rdmmm->log("update"); - } search_for_drives(); if(check)check_and_notify(); return !m_current_drives.empty(); @@ -474,7 +470,7 @@ void RemovableDriveManager::check_and_notify() //std::cout<<"drives count: "<log("drives count not same"); + //m_rdmmm->log("drives count not same"); //std::cout<<" vs "<< m_current_drives.size(); if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { @@ -505,13 +501,16 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) } bool RemovableDriveManager::is_last_drive_removed() { + std::cout<<"is last: "< Date: Thu, 12 Dec 2019 10:48:33 +0100 Subject: [PATCH 045/162] eject button after export --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/RemovableDriveManager.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 258e338719..bdaf8f8a79 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -272,7 +272,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); -#if __linux__ +#if !__APPLE__ RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); #endif diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a0e453abc3..74a26c4002 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4052,7 +4052,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const if (sidebar->show_reslice(false) | sidebar->show_export(true) | sidebar->show_send(send_gcode_shown) | - sidebar->show_disconnect(disconnect_shown)) + sidebar->show_disconnect(false/*disconnect_shown*/)) sidebar->Layout(); } else @@ -4603,12 +4603,13 @@ void Plater::export_gcode() fs::path path = into_path(dlg.GetPath()); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = std::move(path); - RemovableDriveManager::get_instance().update(0, true); - RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); - } if (! output_path.empty()) + { + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); p->export_gcode(std::move(output_path), PrintHostJob()); + } } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index d5f2244095..7ab34204bc 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -410,7 +410,7 @@ void RemovableDriveManager::init() { //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 - register_window(); + //register_window(); #elif __APPLE__ m_rdmmm->register_window(); #endif @@ -501,16 +501,16 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) } bool RemovableDriveManager::is_last_drive_removed() { - std::cout<<"is last: "< Date: Thu, 12 Dec 2019 14:56:30 +0100 Subject: [PATCH 046/162] button show after write --- src/slic3r/GUI/Plater.cpp | 8 ++++-- src/slic3r/GUI/RemovableDriveManager.cpp | 35 +++--------------------- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +-- 3 files changed, 10 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 74a26c4002..3ecb174ce9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3171,6 +3171,7 @@ void Plater::priv::update_fff_scene() this->preview->reload_print(); // In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: view3D->reload_scene(true); + show_action_buttons(false); } void Plater::priv::update_sla_scene() @@ -4052,7 +4053,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const if (sidebar->show_reslice(false) | sidebar->show_export(true) | sidebar->show_send(send_gcode_shown) | - sidebar->show_disconnect(false/*disconnect_shown*/)) + sidebar->show_disconnect(disconnect_shown)) sidebar->Layout(); } else @@ -4606,9 +4607,10 @@ void Plater::export_gcode() } if (! output_path.empty()) { - RemovableDriveManager::get_instance().update(0, true); - RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); + std::string path = output_path.string(); p->export_gcode(std::move(output_path), PrintHostJob()); + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().set_last_save_path(path); } } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7ab34204bc..cd360b580f 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -24,9 +24,6 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, namespace Slic3r { namespace GUI { -//std::vector RemovableDriveManager::m_current_drives; -//std::vector> RemovableDriveManager::m_callbacks; - #if _WIN32 INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -42,7 +39,6 @@ void RemovableDriveManager::search_for_drives() std::string path (1,(char)('A' + i)); path+=":"; UINT drive_type = GetDriveTypeA(path.c_str()); - //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) { path += "\\"; @@ -74,12 +69,9 @@ void RemovableDriveManager::search_for_drives() } } } - //std::cout << "found drives:" << m_current_drives.size() << "\n"; } void RemovableDriveManager::eject_drive(const std::string &path) { - - //if (!update() || !is_drive_mounted(path)) if(m_current_drives.empty()) return; for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) @@ -88,7 +80,6 @@ void RemovableDriveManager::eject_drive(const std::string &path) { std::string mpath = "\\\\.\\" + path; mpath = mpath.substr(0, mpath.size() - 1); - //std::cout << "Ejecting " << mpath << "\n"; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { @@ -138,7 +129,7 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) } void RemovableDriveManager::register_window() { - std::cout << "Registering for device notification\n"; + //creates new unvisible window that is recieving callbacks from system WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; @@ -181,9 +172,6 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP LRESULT lRet = 1; static HDEVNOTIFY hDeviceNotify; - static HWND hEditWnd; - static ULONGLONG msgCount = 0; - switch (message) { case WM_CREATE: @@ -194,11 +182,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; NotificationFilter.dbcc_classguid = WceusbshGUID; - hDeviceNotify = RegisterDeviceNotification( - hWnd, // events recipient - &NotificationFilter, // type of device - DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle - ); + hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); break; case WM_DEVICECHANGE: @@ -280,7 +264,6 @@ void RemovableDriveManager::search_for_drives() } - //std::cout << "found drives:" < RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - //std::cout<<"drives count: "<log("drives count not same"); - //std::cout<<" vs "<< m_current_drives.size(); if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) @@ -481,7 +461,6 @@ void RemovableDriveManager::check_and_notify() } m_drives_count = m_current_drives.size(); } - //std::cout<<"\n"; } void RemovableDriveManager::add_callback(std::function callback) { @@ -522,10 +501,4 @@ void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } - -void RemovableDriveManager::print() -{ - //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; - std::cout << "notified\n"; -} -}}//namespace Slicer::Gui:: +}}//namespace Slicer::Gui diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 9eea355f79..b4fc71e265 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -32,7 +32,7 @@ public: //update() searches for removable devices, returns false if empty. void init(); - bool update(const long time = 0, bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0,const bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_save_path(); @@ -44,8 +44,6 @@ public: void set_last_save_path(const std::string &path); bool is_last_drive_removed(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() - void print(); - private: RemovableDriveManager(); void search_for_drives(); From e1d9de3ca425cedaa239106dd67d0055751d2e30 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 12 Dec 2019 15:43:14 +0100 Subject: [PATCH 047/162] button show after write --- src/slic3r/GUI/Plater.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3ecb174ce9..417afa0a96 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3171,7 +3171,7 @@ void Plater::priv::update_fff_scene() this->preview->reload_print(); // In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: view3D->reload_scene(true); - show_action_buttons(false); + } void Plater::priv::update_sla_scene() @@ -3518,6 +3518,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) default: break; } + show_action_buttons(false); + if (canceled) { if (wxGetApp().get_mode() == comSimple) sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now"); From ff58fa99f41f315e1f03ee330ea7b528e5c65f55 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 13 Dec 2019 11:52:08 +0100 Subject: [PATCH 048/162] comments --- src/slic3r/GUI/RemovableDriveManager.cpp | 24 ++++++++++++++++++---- src/slic3r/GUI/RemovableDriveManager.hpp | 26 ++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index cd360b580f..02681b7daf 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -30,7 +30,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); - m_current_drives.reserve(26); + //get logical drives flags by letter in alphabetical order DWORD drives_mask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { @@ -39,6 +39,7 @@ void RemovableDriveManager::search_for_drives() std::string path (1,(char)('A' + i)); path+=":"; UINT drive_type = GetDriveTypeA(path.c_str()); + // DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives) if (drive_type == DRIVE_REMOVABLE) { // get name of drive @@ -51,10 +52,12 @@ void RemovableDriveManager::search_for_drives() BOOL error = GetVolumeInformationW(wpath.c_str(), &volume_name[0], sizeof(volume_name), NULL, NULL, NULL, &file_system_name[0], sizeof(file_system_name)); if(error != 0) { + /* if (volume_name == L"") { volume_name = L"REMOVABLE DRIVE"; } + */ if (file_system_name != L"") { ULARGE_INTEGER free_space; @@ -78,6 +81,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) { if ((*it).path == path) { + // get handle to device std::string mpath = "\\\\.\\" + path; mpath = mpath.substr(0, mpath.size() - 1); HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); @@ -87,8 +91,12 @@ void RemovableDriveManager::eject_drive(const std::string &path) return; } DWORD deviceControlRetVal(0); + //these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger. + //sd cards does trigger WM_DEVICECHANGE messege, usb drives dont + DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + // some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); if (error == 0) { @@ -130,11 +138,12 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) void RemovableDriveManager::register_window() { //creates new unvisible window that is recieving callbacks from system + // structure to register WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); - wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback); + wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback);//this is callback wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); @@ -169,6 +178,9 @@ void RemovableDriveManager::register_window() INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + // here we need to catch messeges about device removal + // problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device. + //uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates LRESULT lRet = 1; static HDEVNOTIFY hDeviceNotify; @@ -187,6 +199,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP case WM_DEVICECHANGE: { + // here is the important if(wParam == DBT_DEVICEREMOVECOMPLETE) { - RemovableDriveManager::get_instance().update(0, true); @@ -207,9 +220,9 @@ void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); - m_current_drives.reserve(26); #if __APPLE__ + // if on macos obj-c class will enumerate if(m_rdmmm) { m_rdmmm->list_devices(); @@ -287,6 +300,8 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin } void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path) { + //confirms if the file is removable drive and adds it to vector + //if not same file system - could be removable drive if(!compare_filesystem_id(path, parent_path)) { @@ -335,7 +350,8 @@ void RemovableDriveManager::eject_drive(const std::string &path) } } std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; - +// there is no usable command in c++ so terminal command is used instead +// but neither triggers "succesful safe removal messege" std::string command = ""; #if __APPLE__ command = "diskutil unmount "; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index b4fc71e265..ac1645df7b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -29,26 +29,34 @@ public: } RemovableDriveManager(RemovableDriveManager const&) = delete; void operator=(RemovableDriveManager const&) = delete; - - //update() searches for removable devices, returns false if empty. + //call only once. on apple register for unmnount callbacks. on windows register for device notification is prepared but not called (eject usb drive on widnows doesnt trigger the callback, sdc ard does), also enumerates devices for first time so init shoud be called on linux too. void init(); - bool update(const long time = 0,const bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() + //update() searches for removable devices, returns false if empty. /time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0,const bool check = false); bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); + //returns path to last drive which was used, if none was used, returns device that was enumerated last std::string get_last_save_path(); + //returns path to last drive which was used, if none was used, returns empty string std::string get_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); - void add_callback(std::function callback); // callback will notify only if device with last save path was removed - void erase_callbacks(); // erases all callbacks added by add_callback() + // callback will notify only if device with last save path was removed + void add_callback(std::function callback); + // erases all callbacks added by add_callback() + void erase_callbacks(); + // marks one of the eveices in vector as last used void set_last_save_path(const std::string &path); bool is_last_drive_removed(); - bool is_last_drive_removed_with_update(const long time = 0); // param as update() + // param as update() + bool is_last_drive_removed_with_update(const long time = 0); private: RemovableDriveManager(); void search_for_drives(); + //triggers callbacks if last used drive was removed void check_and_notify(); - std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" + //returns drive path (same as path in DriveData) if exists otherwise empty string "" + std::string get_drive_from_path(const std::string& path); void reset_last_save_path(); std::vector m_current_drives; @@ -58,8 +66,8 @@ private: std::string m_last_save_path; #if _WIN32 + //registers for notifications by creating invisible window void register_window(); - //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #else #if __APPLE__ RDMMMWrapper * m_rdmmm; @@ -69,7 +77,7 @@ private: void inspect_file(const std::string &path, const std::string &parent_path); #endif }; - +// apple wrapper for RemovableDriveManagerMM which searches for drives and/or ejects them #if __APPLE__ class RDMMMWrapper { From 8895e944cf2deca3b894415ba05fe281af4a7456 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 13 Dec 2019 13:04:09 +0100 Subject: [PATCH 049/162] comments --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 417afa0a96..0dc09d9d81 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3517,7 +3517,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) break; default: break; } - + //added to show disconnect_button after writing show_action_buttons(false); if (canceled) { From e5fcb587e2bbff1313da989924792c44cd4f4a92 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 13 Dec 2019 13:23:55 +0100 Subject: [PATCH 050/162] Implemented rescaling for "Remove device" button --- src/slic3r/GUI/Plater.cpp | 58 ++++++++++++++++++--------------- src/slic3r/GUI/wxExtensions.cpp | 8 +++-- src/slic3r/GUI/wxExtensions.hpp | 7 ++++ 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 417afa0a96..814bcde0cf 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -699,8 +699,8 @@ struct Sidebar::priv wxButton *btn_export_gcode; wxButton *btn_reslice; - wxButton *btn_send_gcode; - ScalableButton *btn_disconnect; + ScalableButton *btn_send_gcode; + ScalableButton *btn_remove_device; priv(Plater *plater) : plater(plater) {} ~priv(); @@ -849,25 +849,30 @@ Sidebar::Sidebar(Plater *parent) // Buttons underneath the scrolled area - auto init_btn = [this](wxButton **btn, wxString label, const std::string icon_name = "", wxString tooltip = wxEmptyString) { - *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, - wxDefaultSize, wxBU_EXACTFIT); - (*btn)->SetFont(wxGetApp().bold_font()); - (*btn)->SetToolTip(tooltip); + // rescalable bitmap buttons "Send to printer" and "Remove device" - if (!icon_name.empty()) - (*btn)->SetBitmap(create_scaled_bitmap(this, icon_name)); + auto init_scalable_btn = [this](ScalableButton** btn, const std::string& icon_name, wxString tooltip = wxEmptyString) + { + ScalableBitmap bmp = ScalableBitmap(this, icon_name, int(2.5 * wxGetApp().em_unit())); + *btn = new ScalableButton(this, wxID_ANY, bmp, "", wxBU_EXACTFIT); + (*btn)->SetToolTip(tooltip); + (*btn)->Hide(); }; - init_btn(&p->btn_send_gcode, /*_(L("Send to printer"))*/"", "export_gcode", _(L("Send to printer"))); - p->btn_send_gcode->Hide(); - init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots); - init_btn(&p->btn_reslice, _(L("Slice now"))); + init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer"))); + init_scalable_btn(&p->btn_remove_device, "revert_all_" , _(L("Remove device"))); - p->btn_disconnect = new ScalableButton(this, wxID_ANY, "revert_all_", "", - wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT); - p->btn_disconnect->Hide(); - p->btn_disconnect->SetToolTip(_(L("Remove device"))); + // regular buttons "Slice now" and "Export G-code" + + const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4; + auto init_btn = [this](wxButton **btn, wxString label, const int button_height) { + *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, + wxSize(-1, button_height), wxBU_EXACTFIT); + (*btn)->SetFont(wxGetApp().bold_font()); + }; + + init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots , scaled_height); + init_btn(&p->btn_reslice , _(L("Slice now")) , scaled_height); enable_buttons(false); @@ -876,12 +881,10 @@ Sidebar::Sidebar(Plater *parent) auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); complect_btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND); - complect_btns_sizer->Add(p->btn_disconnect); + complect_btns_sizer->Add(p->btn_remove_device); btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5); -// btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); -// btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(p->scrolled, 1, wxEXPAND); @@ -900,10 +903,7 @@ Sidebar::Sidebar(Plater *parent) p->plater->select_view_3D("Preview"); }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); - p->btn_disconnect->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { - // #dk_FIXME - p->plater->eject_drive(); - }); + p->btn_remove_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); }); } Sidebar::~Sidebar() {} @@ -1049,6 +1049,12 @@ void Sidebar::msw_rescale() p->object_info->msw_rescale(); + p->btn_send_gcode->msw_rescale(); + p->btn_remove_device->msw_rescale(); + const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4; + p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height)); + p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height)); + p->scrolled->Layout(); } @@ -1277,13 +1283,13 @@ void Sidebar::enable_buttons(bool enable) p->btn_reslice->Enable(enable); p->btn_export_gcode->Enable(enable); p->btn_send_gcode->Enable(enable); - p->btn_disconnect->Enable(enable); + p->btn_remove_device->Enable(enable); } bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); } bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); } bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); } -bool Sidebar::show_disconnect(bool show)const { return p->btn_disconnect->Show(show); } +bool Sidebar::show_disconnect(bool show)const { return p->btn_remove_device->Show(show); } bool Sidebar::is_multifilament() { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8493138971..735e704ee8 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -3935,8 +3935,10 @@ ScalableButton::ScalableButton( wxWindow * parent, const ScalableBitmap& bitmap, const wxString& label /*= wxEmptyString*/, long style /*= wxBU_EXACTFIT | wxNO_BORDER*/) : + m_parent(parent), m_current_icon_name(bitmap.name()), - m_parent(parent) + m_px_cnt(bitmap.px_cnt()), + m_is_horizontal(bitmap.is_horizontal()) { Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style); #ifdef __WXMSW__ @@ -3961,9 +3963,9 @@ void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp) void ScalableButton::msw_rescale() { - SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name)); + SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt, m_is_horizontal)); if (!m_disabled_icon_name.empty()) - SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name)); + SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name, m_px_cnt, m_is_horizontal)); if (m_width > 0 || m_height>0) { diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 7841b62fee..951f7ea8f4 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -729,6 +729,9 @@ public: wxBitmap& bmp() { return m_bmp; } const std::string& name() const{ return m_icon_name; } + int px_cnt()const {return m_px_cnt;} + bool is_horizontal()const {return m_is_horizontal;} + private: wxWindow* m_parent{ nullptr }; wxBitmap m_bmp = wxBitmap(); @@ -1116,6 +1119,10 @@ private: std::string m_disabled_icon_name = ""; int m_width {-1}; // should be multiplied to em_unit int m_height{-1}; // should be multiplied to em_unit + + // bitmap dimensions + int m_px_cnt{ 16 }; + bool m_is_horizontal{ false }; }; From 8b4732e811fcca736c6e8a78b1d03c441d30ea2c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 26 Nov 2019 14:19:29 +0100 Subject: [PATCH 051/162] removable drive manager - Windows part --- src/slic3r/GUI/AppConfig.cpp | 5 + src/slic3r/GUI/RemovableDriveManager.cpp | 149 +++++++++++++++++++++++ src/slic3r/GUI/RemovableDriveManager.hpp | 41 +++++++ 3 files changed, 195 insertions(+) create mode 100644 src/slic3r/GUI/RemovableDriveManager.cpp create mode 100644 src/slic3r/GUI/RemovableDriveManager.hpp diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index d33d945efb..4f3272e264 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -21,6 +21,7 @@ #include #include "I18N.hpp" +#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -357,6 +358,10 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { + if (GUI::RemovableDriveManager::getInstance().update()) + { + return GUI::RemovableDriveManager::getInstance().getLastDrivePath(); + } const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp new file mode 100644 index 0000000000..44d4181d1b --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -0,0 +1,149 @@ +#include "RemovableDriveManager.hpp" + +#include +#include +#include +#include + +//#include +//#include "libslic3r/Utils.hpp" + +DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, + 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); + +namespace Slic3r { +namespace GUI { + +std::vector RemovableDriveManager::currentDrives; + +bool RemovableDriveManager::update() +{ + searchForDrives(currentDrives); + return !currentDrives.empty(); +} +void RemovableDriveManager::searchForDrives(std::vector& newDrives) +{ + newDrives.clear(); + newDrives.reserve(26); + DWORD drivesMask = GetLogicalDrives(); + for (size_t i = 0; i < 26; i++) + { + if(drivesMask & (1 << i)) + { + std::string path (1,(char)('A' + i)); + path+=":"; + UINT driveType = GetDriveTypeA(path.c_str()); + //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) + { + newDrives.push_back(DriveData(volumeName, path)); + } + } + } + } + else if(driveType == 3)//disks and usb drives + { + } + } + } + +} + +void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) +{ + currentDrives.clear(); + currentDrives.reserve(26); + for (auto it = newDrives.begin(); it != newDrives.end(); ++it) + { + currentDrives.push_back(*it); + } +} +void RemovableDriveManager::printDrivesToLog() +{ + //std::cout<<"current drives:"<< currentDrives.size() <<"\n"; + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + //BOOST_LOG_TRIVIAL(trace) << boost::format("found disk %1%:") % ('A' + i); + //std::cout << /*std::string((*it).name.begin(), (*it).name.end()) << "(" << */(*it).path << ":/, "; + } + //std::cout << "\n"; +} +bool RemovableDriveManager::isDriveMounted(std::string path) +{ + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + return true; + } + } + return false; +} +void RemovableDriveManager::ejectDrive(std::string path) +{ + if (!update() || !isDriveMounted(path)) + return; + + path = "\\\\.\\"+path; + HANDLE handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if(handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << path << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0,nullptr , 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if(error != 0) + std::cout << "Ejected " << path << "\n"; + else + std::cerr << "Ejecting " << path << " failed "<< deviceControlRetVal << " " << GetLastError() <<" \n"; + + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + currentDrives.erase(it); + break; + } + } +} +std::string RemovableDriveManager::getLastDrivePath() +{ + if (!currentDrives.empty()) + { + return currentDrives.back().path; + } + return ""; +} +void RemovableDriveManager::getAllDrives(std::vector& drives) +{ + drives.clear(); + drives.reserve(26); + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + drives.push_back(*it); + } +} +}} \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp new file mode 100644 index 0000000000..cab58fee6c --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -0,0 +1,41 @@ +#ifndef slic3r_GUI_RemovableDriveManager_hpp_ +#define slic3r_GUI_RemovableDriveManager_hpp_ + +#include +#include + +namespace Slic3r { +namespace GUI { +struct DriveData +{ + std::wstring name; + std::string path; + DriveData(std::wstring n, std::string p):name(n),path(p){} +}; +class RemovableDriveManager +{ +public: + static RemovableDriveManager& getInstance() + { + static RemovableDriveManager instance; + return instance; + } + RemovableDriveManager(RemovableDriveManager const&) = delete; + void operator=(RemovableDriveManager const&) = delete; + + //update() searches for removable devices, returns false if empty. + static bool update(); + static bool isDriveMounted(std::string path); + static void ejectDrive(std::string path); + static std::string getLastDrivePath(); + static void getAllDrives(std::vector& drives); +private: + RemovableDriveManager(){} + static void searchForDrives(std::vector& newDrives); + static void printDrivesToLog(); + static void updateCurrentDrives(const std::vector& newDrives); + static std::vector currentDrives; + +}; +}} +#endif \ No newline at end of file From 04ef585124bfc65c745ccbeada994dc7c6ac7bb0 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 26 Nov 2019 15:52:18 +0100 Subject: [PATCH 052/162] removable drives manager linux part --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/RemovableDriveManager.cpp | 166 +++++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.hpp | 10 +- 3 files changed, 134 insertions(+), 44 deletions(-) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index bcddcfe069..2d7b99b73d 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -111,6 +111,8 @@ set(SLIC3R_GUI_SOURCES GUI/WipeTowerDialog.hpp GUI/RammingChart.cpp GUI/RammingChart.hpp + GUI/RemovableDriveManager.cpp + GUI/RemovableDriveManager.hpp GUI/BonjourDialog.cpp GUI/BonjourDialog.hpp GUI/ButtonsDescription.cpp diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 44d4181d1b..ae718b7d3a 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,26 +1,34 @@ #include "RemovableDriveManager.hpp" -#include -#include + + #include #include -//#include -//#include "libslic3r/Utils.hpp" +#if _WIN32 +#include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); +#else +//linux includes +#include +#include +#include +#include +#include +#endif namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::currentDrives; -bool RemovableDriveManager::update() -{ - searchForDrives(currentDrives); - return !currentDrives.empty(); -} + + + +#if _WIN32 void RemovableDriveManager::searchForDrives(std::vector& newDrives) { newDrives.clear(); @@ -69,37 +77,6 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) } } - -void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) -{ - currentDrives.clear(); - currentDrives.reserve(26); - for (auto it = newDrives.begin(); it != newDrives.end(); ++it) - { - currentDrives.push_back(*it); - } -} -void RemovableDriveManager::printDrivesToLog() -{ - //std::cout<<"current drives:"<< currentDrives.size() <<"\n"; - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - //BOOST_LOG_TRIVIAL(trace) << boost::format("found disk %1%:") % ('A' + i); - //std::cout << /*std::string((*it).name.begin(), (*it).name.end()) << "(" << */(*it).path << ":/, "; - } - //std::cout << "\n"; -} -bool RemovableDriveManager::isDriveMounted(std::string path) -{ - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - if ((*it).path == path) - { - return true; - } - } - return false; -} void RemovableDriveManager::ejectDrive(std::string path) { if (!update() || !isDriveMounted(path)) @@ -129,6 +106,115 @@ void RemovableDriveManager::ejectDrive(std::string path) } } } +#else +void RemovableDriveManager::searchForDrives(std::vector& newDrives) +{ + struct stat buf; + std::string path(std::getenv("USER")); + std::string pp(path); + + newDrives.clear(); + newDrives.reserve(26); + + //search /media/* folder + stat("/media/",&buf); + std::cout << "/media ID: " <& newDrives,const std::string path, const dev_t parentDevID) +{ + glob_t globbuf; + globbuf.gl_offs = 2; + std::cout<<"searching "<& newDrives) +{ + currentDrives.clear(); + currentDrives.reserve(26); + for (auto it = newDrives.begin(); it != newDrives.end(); ++it) + { + currentDrives.push_back(*it); + } +} +bool RemovableDriveManager::isDriveMounted(std::string path) +{ + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + return true; + } + } + return false; +} + std::string RemovableDriveManager::getLastDrivePath() { if (!currentDrives.empty()) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index cab58fee6c..c503fdf187 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -8,9 +8,9 @@ namespace Slic3r { namespace GUI { struct DriveData { - std::wstring name; + std::string name; std::string path; - DriveData(std::wstring n, std::string p):name(n),path(p){} + DriveData(std::string n, std::string p):name(n),path(p){} }; class RemovableDriveManager { @@ -32,10 +32,12 @@ public: private: RemovableDriveManager(){} static void searchForDrives(std::vector& newDrives); - static void printDrivesToLog(); static void updateCurrentDrives(const std::vector& newDrives); static std::vector currentDrives; - +#if _WIN32 +#else + static void searchPath(std::vector& newDrives,const std::string path, const dev_t parentDevID); +#endif }; }} #endif \ No newline at end of file From b8b4b1dd42953ceedf7a5a4e36433a7d01e2d28a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 11:33:36 +0100 Subject: [PATCH 053/162] refactoring --- src/slic3r/GUI/AppConfig.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.cpp | 116 ++++++++++------------- src/slic3r/GUI/RemovableDriveManager.hpp | 15 ++- 3 files changed, 58 insertions(+), 75 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 4f3272e264..26ca07082d 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -360,7 +360,7 @@ std::string AppConfig::get_last_output_dir(const std::string &alt) const { if (GUI::RemovableDriveManager::getInstance().update()) { - return GUI::RemovableDriveManager::getInstance().getLastDrivePath(); + return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); } const auto it = m_storage.find(""); if (it != m_storage.end()) { diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ae718b7d3a..53515ccdcb 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,14 +1,12 @@ #include "RemovableDriveManager.hpp" - - - #include #include - +#include "boost/nowide/convert.hpp" #if _WIN32 #include #include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); #else @@ -23,16 +21,13 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, namespace Slic3r { namespace GUI { -std::vector RemovableDriveManager::currentDrives; - - - +std::vector RemovableDriveManager::m_current_drives; #if _WIN32 -void RemovableDriveManager::searchForDrives(std::vector& newDrives) +void RemovableDriveManager::search_for_drives() { - newDrives.clear(); - newDrives.reserve(26); + m_current_drives.clear(); + m_current_drives.reserve(26); DWORD drivesMask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { @@ -65,7 +60,7 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) //std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n"; if (freeSpace.QuadPart > 0) { - newDrives.push_back(DriveData(volumeName, path)); + m_current_drives.push_back(DriveData(boost::nowide::narrow(volumeName), path)); } } } @@ -77,49 +72,51 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) } } -void RemovableDriveManager::ejectDrive(std::string path) +void RemovableDriveManager::eject_drive(const std::string &path) { - if (!update() || !isDriveMounted(path)) - return; - path = "\\\\.\\"+path; - HANDLE handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - if(handle == INVALID_HANDLE_VALUE) - { - std::cerr << "Ejecting " << path << " failed " << GetLastError() << " \n"; + //if (!update() || !is_drive_mounted(path)) + if(m_current_drives.empty()) return; - } - DWORD deviceControlRetVal(0); - BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0,nullptr , 0, &deviceControlRetVal, nullptr); - CloseHandle(handle); - if(error != 0) - std::cout << "Ejected " << path << "\n"; - else - std::cerr << "Ejecting " << path << " failed "<< deviceControlRetVal << " " << GetLastError() <<" \n"; - - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { - currentDrives.erase(it); + std::string mpath = "\\\\.\\" + path; + HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if (handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if (error != 0) + std::cout << "Ejected " << mpath << "\n"; + else + std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + + + m_current_drives.erase(it); break; } } } #else -void RemovableDriveManager::searchForDrives(std::vector& newDrives) +void RemovableDriveManager::search_for_drives() { struct stat buf; std::string path(std::getenv("USER")); std::string pp(path); - newDrives.clear(); - newDrives.reserve(26); + m_current_drives.clear(); + m_current_Drives.reserve(26); //search /media/* folder stat("/media/",&buf); std::cout << "/media ID: " <& newDrives) stat(pp.c_str() ,&buf); std::cout << pp <<" ID: " <& newDrives,const std::string path, const dev_t parentDevID) +void RemovableDriveManager::search_path(const std::string &path,const dev_t &parentDevID) { glob_t globbuf; globbuf.gl_offs = 2; @@ -159,17 +156,17 @@ void RemovableDriveManager::searchPath(std::vector& newDrives,const s std::cout << buf.st_dev << "\n"; if(buf.st_dev != parentDevID)// not same file system { - newDrives.push_back(DriveData(name,globbuf.gl_pathv[i])); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); } } globfree(&globbuf); } -void RemovableDriveManager::ejectDrive(std::string path) +void RemovableDriveManager::eject_drive(const std::string &path) { - if (currentDrives.empty()) + if (m_current_drives.empty()) return; - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if((*it).path == path) { @@ -180,7 +177,7 @@ void RemovableDriveManager::ejectDrive(std::string path) int errsv = errno; std::cerr<<"Ejecting failed Error "<< errsv<<"\n"; } - currentDrives.erase(it); + m_current_drives.erase(it); break; } @@ -190,22 +187,14 @@ void RemovableDriveManager::ejectDrive(std::string path) #endif bool RemovableDriveManager::update() { - searchForDrives(currentDrives); - return !currentDrives.empty(); + search_for_drives(); + return !m_current_drives.empty(); } -void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) + +bool RemovableDriveManager::is_drive_mounted(const std::string &path) { - currentDrives.clear(); - currentDrives.reserve(26); - for (auto it = newDrives.begin(); it != newDrives.end(); ++it) - { - currentDrives.push_back(*it); - } -} -bool RemovableDriveManager::isDriveMounted(std::string path) -{ - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { @@ -215,21 +204,16 @@ bool RemovableDriveManager::isDriveMounted(std::string path) return false; } -std::string RemovableDriveManager::getLastDrivePath() +std::string RemovableDriveManager::get_last_drive_path() { - if (!currentDrives.empty()) + if (!m_current_drives.empty()) { - return currentDrives.back().path; + return m_current_drives.back().path; } return ""; } -void RemovableDriveManager::getAllDrives(std::vector& drives) +std::vector RemovableDriveManager::get_all_drives() { - drives.clear(); - drives.reserve(26); - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - drives.push_back(*it); - } + return m_current_drives; } }} \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c503fdf187..8270c0f0fb 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -25,18 +25,17 @@ public: //update() searches for removable devices, returns false if empty. static bool update(); - static bool isDriveMounted(std::string path); - static void ejectDrive(std::string path); - static std::string getLastDrivePath(); - static void getAllDrives(std::vector& drives); + static bool is_drive_mounted(const std::string &path); + static void eject_drive(const std::string &path); + static std::string get_last_drive_path(); + static std::vector get_all_drives(); private: RemovableDriveManager(){} - static void searchForDrives(std::vector& newDrives); - static void updateCurrentDrives(const std::vector& newDrives); - static std::vector currentDrives; + static void search_for_drives(); + static std::vector m_current_drives; #if _WIN32 #else - static void searchPath(std::vector& newDrives,const std::string path, const dev_t parentDevID); + static void search_path(const std::string &path, const dev_t &parentDevID); #endif }; }} From 852d8ad5ccac07176ad156d802c637dd1d828a20 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 13:30:45 +0100 Subject: [PATCH 054/162] check if last path is on rem drive --- src/slic3r/GUI/AppConfig.cpp | 6 +---- src/slic3r/GUI/Plater.cpp | 9 ++++++- src/slic3r/GUI/RemovableDriveManager.cpp | 30 +++++++++++++++++++++++- src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 26ca07082d..7055822513 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -21,7 +21,6 @@ #include #include "I18N.hpp" -#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -358,10 +357,7 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { - if (GUI::RemovableDriveManager::getInstance().update()) - { - return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); - } + const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c8267331d3..efe0ab7b31 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -77,6 +77,7 @@ #include "../Utils/FixModelByWin10.hpp" #include "../Utils/UndoRedo.hpp" #include "../Utils/Thread.hpp" +#include "RemovableDriveManager.hpp" #include // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" @@ -4661,7 +4662,13 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - + if (GUI::RemovableDriveManager::getInstance().update()) + { + if (!RemovableDriveManager::getInstance().is_path_on_removable_drive(start_dir)) + { + start_dir = RemovableDriveManager::getInstance().get_last_drive_path(); + } + } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), start_dir, from_path(default_output_file.filename()), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 53515ccdcb..776334bf22 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); #else @@ -208,7 +209,11 @@ std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { +#if _WIN32 + return m_current_drives.back().path + "\\"; +#else return m_current_drives.back().path; +#endif } return ""; } @@ -216,4 +221,27 @@ std::vector RemovableDriveManager::get_all_drives() { return m_current_drives; } -}} \ No newline at end of file +#if _WIN32 +bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path) +{ + if (m_current_drives.empty()) + return false; + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return true; + } + return false; +} +#else +bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path, const std::string& drive) +{ + if (m_current_drives.empty()) + return false; + + return false; +} +#endif +}}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 8270c0f0fb..3de9d72cee 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -29,6 +29,7 @@ public: static void eject_drive(const std::string &path); static std::string get_last_drive_path(); static std::vector get_all_drives(); + static bool is_path_on_removable_drive(const std::string &path); private: RemovableDriveManager(){} static void search_for_drives(); From 6e9a37e81bd4e91f59a68c3a2104aa0c7cfa3cab Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 14:30:10 +0100 Subject: [PATCH 055/162] prev commit linux part --- src/slic3r/GUI/RemovableDriveManager.cpp | 139 ++++++++++++----------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 776334bf22..2d1f4ba6f2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -29,46 +29,43 @@ void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); m_current_drives.reserve(26); - DWORD drivesMask = GetLogicalDrives(); + DWORD drives_mask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { - if(drivesMask & (1 << i)) + if(drives_mask & (1 << i)) { std::string path (1,(char)('A' + i)); path+=":"; - UINT driveType = GetDriveTypeA(path.c_str()); + UINT drive_type = GetDriveTypeA(path.c_str()); //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) + if (free_space.QuadPart > 0) { - m_current_drives.push_back(DriveData(boost::nowide::narrow(volumeName), path)); + m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); } } } } - else if(driveType == 3)//disks and usb drives - { - } } } @@ -93,10 +90,10 @@ void RemovableDriveManager::eject_drive(const std::string &path) DWORD deviceControlRetVal(0); BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); CloseHandle(handle); - if (error != 0) - std::cout << "Ejected " << mpath << "\n"; - else + if (error == 0) + { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + } m_current_drives.erase(it); @@ -104,6 +101,19 @@ void RemovableDriveManager::eject_drive(const std::string &path) } } } +bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) +{ + if (m_current_drives.empty()) + return false; + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return true; + } + return false; +} #else void RemovableDriveManager::search_for_drives() { @@ -112,11 +122,11 @@ void RemovableDriveManager::search_for_drives() std::string pp(path); m_current_drives.clear(); - m_current_Drives.reserve(26); + m_current_drives.reserve(26); //search /media/* folder stat("/media/",&buf); - std::cout << "/media ID: " < RemovableDriveManager::get_all_drives() return m_current_drives; } #if _WIN32 -bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path) -{ - if (m_current_drives.empty()) - return false; - int letter = PathGetDriveNumberA(path.c_str()); - for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) - { - char drive = (*it).path[0]; - if (drive == ('A' + letter)) - return true; - } - return false; -} -#else -bool RemovableDriveManager::is_path_on_removable_drive(const std::string& path, const std::string& drive) -{ - if (m_current_drives.empty()) - return false; - return false; -} +#else + #endif }}//namespace Slicer::Gui:: \ No newline at end of file From 1790c795fbdc4a2cca1006bd0e4f686f0e77ca2e Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 15:47:37 +0100 Subject: [PATCH 056/162] rdm update every 2 seconds --- src/slic3r/GUI/GUI_App.cpp | 2 ++ src/slic3r/GUI/RemovableDriveManager.cpp | 15 ++++++++++++++- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e02dd5f6e7..3d09e3573b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -46,6 +46,7 @@ #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" #include "UpdateDialogs.hpp" +#include "RemovableDriveManager.hpp" #ifdef __WXMSW__ #include @@ -271,6 +272,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); + RemovableDriveManager::getInstance().update(wxGetLocalTime()); // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 2d1f4ba6f2..235e1ccbe8 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -23,6 +23,7 @@ namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::m_current_drives; +long RemovableDriveManager::m_last_update = 0; #if _WIN32 void RemovableDriveManager::search_for_drives() @@ -215,8 +216,20 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) return false; } #endif -bool RemovableDriveManager::update() +bool RemovableDriveManager::update(long time) { + if(time != 0) //time = 0 is forced update + { + long diff = m_last_update - time; + if(diff <= -2) + { + m_last_update = time; + }else + { + return false; // return value shouldnt matter if update didnt run + } + } + std::cout << "RDM update " << m_last_update <<"\n"; search_for_drives(); return !m_current_drives.empty(); } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 3de9d72cee..c83b8033c9 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,7 +24,7 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - static bool update(); + static bool update(long time = 0); //time = 0 is forced update static bool is_drive_mounted(const std::string &path); static void eject_drive(const std::string &path); static std::string get_last_drive_path(); @@ -34,6 +34,7 @@ private: RemovableDriveManager(){} static void search_for_drives(); static std::vector m_current_drives; + static long m_last_update; #if _WIN32 #else static void search_path(const std::string &path, const dev_t &parentDevID); From 649f3a2c3ea783648bdf839028debbac76bde9be Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 28 Nov 2019 13:38:08 +0100 Subject: [PATCH 057/162] add_callback function --- src/slic3r/GUI/RemovableDriveManager.cpp | 65 ++++++++++++++++++++---- src/slic3r/GUI/RemovableDriveManager.hpp | 6 ++- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 235e1ccbe8..a1a5d7dd92 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -23,7 +23,8 @@ namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::m_current_drives; -long RemovableDriveManager::m_last_update = 0; +std::vector> RemovableDriveManager::m_callbacks; + #if _WIN32 void RemovableDriveManager::search_for_drives() @@ -69,7 +70,7 @@ void RemovableDriveManager::search_for_drives() } } } - + //std::cout << "found drives:" << m_current_drives.size() << "\n"; } void RemovableDriveManager::eject_drive(const std::string &path) { @@ -115,6 +116,25 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } return false; } +void RemovableDriveManager::register_window() +{ + /* + WNDCLASSEX wndClass; + + wndClass.cbSize = sizeof(WNDCLASSEX); + wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); + wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback); + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); + wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192)); + wndClass.hCursor = LoadCursor(0, IDC_ARROW); + wndClass.lpszClassName = L"SlicerWindowClass"; + wndClass.lpszMenuName = NULL; + wndClass.hIconSm = wndClass.hIcon; + */ +} #else void RemovableDriveManager::search_for_drives() { @@ -218,19 +238,29 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) #endif bool RemovableDriveManager::update(long time) { + static long last_update = 0; + if(last_update == 0) + { + //add_callback(std::bind(&RemovableDriveManager::print, RemovableDriveManager::getInstance())); + add_callback([](void) { print(); }); +#if _WIN32 + register_window(); +#endif + } if(time != 0) //time = 0 is forced update { - long diff = m_last_update - time; + long diff = last_update - time; if(diff <= -2) { - m_last_update = time; + last_update = time; }else { return false; // return value shouldnt matter if update didnt run } } - std::cout << "RDM update " << m_last_update <<"\n"; + //std::cout << "RDM update " << last_update <<"\n"; search_for_drives(); + check_and_notify(); return !m_current_drives.empty(); } @@ -263,9 +293,24 @@ std::vector RemovableDriveManager::get_all_drives() { return m_current_drives; } -#if _WIN32 - -#else - -#endif +void RemovableDriveManager::check_and_notify() +{ + static int number_of_drives = 0; + if(number_of_drives != m_current_drives.size()) + { + for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) + { + (*it)(); + } + number_of_drives = m_current_drives.size(); + } +} +void RemovableDriveManager::add_callback(std::function callback) +{ + m_callbacks.push_back(callback); +} +void RemovableDriveManager::print() +{ + std::cout << "notified\n"; +} }}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c83b8033c9..9f3ebf326b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -30,12 +30,16 @@ public: static std::string get_last_drive_path(); static std::vector get_all_drives(); static bool is_path_on_removable_drive(const std::string &path); + static void add_callback(std::function callback); + static void print(); private: RemovableDriveManager(){} static void search_for_drives(); + static void check_and_notify(); static std::vector m_current_drives; - static long m_last_update; + static std::vector> m_callbacks; #if _WIN32 + static void register_window(); #else static void search_path(const std::string &path, const dev_t &parentDevID); #endif From 735308b794bb84d0a34c4e67de14f9836168abc3 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 28 Nov 2019 13:50:58 +0100 Subject: [PATCH 058/162] refactoring --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 ++--- src/slic3r/GUI/RemovableDriveManager.cpp | 6 ++--- src/slic3r/GUI/RemovableDriveManager.hpp | 30 ++++++++++++------------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 3d09e3573b..e33fc0d2e5 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -272,7 +272,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::getInstance().update(wxGetLocalTime()); + RemovableDriveManager::get_instance().update(wxGetLocalTime()); // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index efe0ab7b31..3e3827926f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4662,11 +4662,11 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - if (GUI::RemovableDriveManager::getInstance().update()) + if (GUI::RemovableDriveManager::get_instance().update()) { - if (!RemovableDriveManager::getInstance().is_path_on_removable_drive(start_dir)) + if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) { - start_dir = RemovableDriveManager::getInstance().get_last_drive_path(); + start_dir = RemovableDriveManager::get_instance().get_last_drive_path(); } } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index a1a5d7dd92..777085165d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -22,8 +22,8 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, namespace Slic3r { namespace GUI { -std::vector RemovableDriveManager::m_current_drives; -std::vector> RemovableDriveManager::m_callbacks; +//std::vector RemovableDriveManager::m_current_drives; +//std::vector> RemovableDriveManager::m_callbacks; #if _WIN32 @@ -242,7 +242,7 @@ bool RemovableDriveManager::update(long time) if(last_update == 0) { //add_callback(std::bind(&RemovableDriveManager::print, RemovableDriveManager::getInstance())); - add_callback([](void) { print(); }); + add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); #endif diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 9f3ebf326b..f3abc42073 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -15,7 +15,7 @@ struct DriveData class RemovableDriveManager { public: - static RemovableDriveManager& getInstance() + static RemovableDriveManager& get_instance() { static RemovableDriveManager instance; return instance; @@ -24,24 +24,24 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - static bool update(long time = 0); //time = 0 is forced update - static bool is_drive_mounted(const std::string &path); - static void eject_drive(const std::string &path); - static std::string get_last_drive_path(); - static std::vector get_all_drives(); - static bool is_path_on_removable_drive(const std::string &path); - static void add_callback(std::function callback); - static void print(); + bool update(long time = 0); //time = 0 is forced update + bool is_drive_mounted(const std::string &path); + void eject_drive(const std::string &path); + std::string get_last_drive_path(); + std::vector get_all_drives(); + bool is_path_on_removable_drive(const std::string &path); + void add_callback(std::function callback); + void print(); private: RemovableDriveManager(){} - static void search_for_drives(); - static void check_and_notify(); - static std::vector m_current_drives; - static std::vector> m_callbacks; + void search_for_drives(); + void check_and_notify(); + std::vector m_current_drives; + std::vector> m_callbacks; #if _WIN32 - static void register_window(); + void register_window(); #else - static void search_path(const std::string &path, const dev_t &parentDevID); + void search_path(const std::string &path, const dev_t &parentDevID); #endif }; }} From 17b146c0a36937287beb519040a7b4446c00935a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 28 Nov 2019 16:35:22 +0100 Subject: [PATCH 059/162] search for rd as root --- src/slic3r/GUI/RemovableDriveManager.cpp | 103 +++++++++++++---------- src/slic3r/GUI/RemovableDriveManager.hpp | 3 +- 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 777085165d..4368d06b64 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,6 +1,5 @@ #include "RemovableDriveManager.hpp" #include -#include #include "boost/nowide/convert.hpp" #if _WIN32 @@ -17,6 +16,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, #include #include #include +#include #endif namespace Slic3r { @@ -96,8 +96,6 @@ void RemovableDriveManager::eject_drive(const std::string &path) { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; } - - m_current_drives.erase(it); break; } @@ -138,65 +136,85 @@ void RemovableDriveManager::register_window() #else void RemovableDriveManager::search_for_drives() { - struct stat buf; - std::string path(std::getenv("USER")); - std::string pp(path); - + m_current_drives.clear(); m_current_drives.reserve(26); //search /media/* folder - stat("/media/",&buf); - //std::cout << "/media ID: " <pw_name; + pp = path; + //search /media/USERNAME/* folder + pp = "/media/"+pp; + path = "/media/" + path + "/*"; + search_path(path, pp); - stat(pp.c_str() ,&buf); - //std::cout << pp <<" ID: " < RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - static int number_of_drives = 0; + static size_t number_of_drives = 0; if(number_of_drives != m_current_drives.size()) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index f3abc42073..43e47a0867 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -41,7 +41,8 @@ private: #if _WIN32 void register_window(); #else - void search_path(const std::string &path, const dev_t &parentDevID); + void search_path(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; }} From 5db80edcd3989e5210513a2673f6d6e0f5977732 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 3 Dec 2019 10:09:53 +0100 Subject: [PATCH 060/162] linux eject --- src/slic3r/GUI/GUI_App.cpp | 1 + src/slic3r/GUI/RemovableDriveManager.cpp | 29 ++++++++++++++---------- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e33fc0d2e5..e6c92cd0a8 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -273,6 +273,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); RemovableDriveManager::get_instance().update(wxGetLocalTime()); + // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 4368d06b64..ec730692fa 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -20,8 +20,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, #endif namespace Slic3r { -namespace GUI { - +namespace GUI { //std::vector RemovableDriveManager::m_current_drives; //std::vector> RemovableDriveManager::m_callbacks; @@ -95,7 +94,10 @@ void RemovableDriveManager::eject_drive(const std::string &path) if (error == 0) { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + return; } + + m_current_drives.erase(it); break; } @@ -179,7 +181,7 @@ void RemovableDriveManager::search_for_drives() } - std::cout << "found drives:" < RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - static size_t number_of_drives = 0; - if(number_of_drives != m_current_drives.size()) + //std::cout<<"drives count: "< callback) { diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 43e47a0867..b465b1c1b8 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -33,11 +33,12 @@ public: void add_callback(std::function callback); void print(); private: - RemovableDriveManager(){} + RemovableDriveManager():m_drives_count(0){} void search_for_drives(); void check_and_notify(); std::vector m_current_drives; std::vector> m_callbacks; + size_t m_drives_count; #if _WIN32 void register_window(); #else From 9b991953e5008e053ce8dd0adf8894bf81a0cd82 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 3 Dec 2019 10:55:38 +0100 Subject: [PATCH 061/162] windows paths --- src/slic3r/GUI/RemovableDriveManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ec730692fa..9b3020e79e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -62,6 +62,7 @@ void RemovableDriveManager::search_for_drives() //std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n"; if (free_space.QuadPart > 0) { + path += "\\"; m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); } } @@ -82,6 +83,8 @@ void RemovableDriveManager::eject_drive(const std::string &path) if ((*it).path == path) { std::string mpath = "\\\\.\\" + path; + mpath = mpath.substr(0, mpath.size() - 1); + std::cout << "Ejecting " << mpath << "\n"; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { @@ -299,11 +302,11 @@ std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { -#if _WIN32 - return m_current_drives.back().path + "\\"; -#else +//#if _WIN32 +// return m_current_drives.back().path + "\\"; +//#else return m_current_drives.back().path; -#endif +//#endif } return ""; } From f651c7b7ec789d4f354e2103a4641f4734f830c7 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 10:05:18 +0100 Subject: [PATCH 062/162] osx search for drives --- src/slic3r/GUI/RemovableDriveManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 9b3020e79e..bdc1727403 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -148,6 +148,9 @@ void RemovableDriveManager::search_for_drives() //search /media/* folder search_path("/media/*", "/media"); + //search /Volumes/* folder (OSX) + search_path("/Volumes/*", "/Volumes"); + std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; From 73ba196e787c4720b778e6021c5574391fea747e Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 11:47:47 +0100 Subject: [PATCH 063/162] linux owner checking --- src/slic3r/GUI/RemovableDriveManager.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index bdc1727403..99520b8429 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -154,7 +154,10 @@ void RemovableDriveManager::search_for_drives() std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; - if(path == "root"){ //if program is run with sudo, we have to search for all users + //if program is run with sudo, we have to search for all users + // but do we want that? + /* + if(path == "root"){ while (true) { passwd* entry = getpwent(); if (!entry) { @@ -174,6 +177,7 @@ void RemovableDriveManager::search_for_drives() } endpwent(); }else + */ { //search /media/USERNAME/* folder pp = "/media/"+pp; @@ -187,7 +191,7 @@ void RemovableDriveManager::search_for_drives() } - //std::cout << "found drives:" <pw_name == username) + { + std::string name = basename(globbuf.gl_pathv[i]); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); + } + } } } }else From 4e3eb89d315a98f1d086cd066c1ea63d23aab724 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:10:08 +0100 Subject: [PATCH 064/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 99520b8429..e1ab1626c5 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -248,6 +248,15 @@ void RemovableDriveManager::eject_drive(const std::string &path) { if((*it).path == path) { + + std::string correct_path(path); + for (size_t i = 0; i < correct_path.size(); ++i) + { + if(correct_path[i]==' ') + { + correct_path = correct_path.insert(i,"\\"); + } + } std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; std::string command = "umount "; command += (*it).path; @@ -301,6 +310,7 @@ bool RemovableDriveManager::update(long time) } search_for_drives(); check_and_notify(); + eject_drive(m_current_drives.back().path); return !m_current_drives.empty(); } From f82bf0d49576bff865d307316a5581a5a6c42893 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:13:18 +0100 Subject: [PATCH 065/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index e1ab1626c5..3ff5735f91 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -255,6 +255,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) if(correct_path[i]==' ') { correct_path = correct_path.insert(i,"\\"); + i++; } } std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; From d2ef01990b93c3baf5e935e8951889a8cd53848d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:18:08 +0100 Subject: [PATCH 066/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 3ff5735f91..7216763eec 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -254,13 +254,13 @@ void RemovableDriveManager::eject_drive(const std::string &path) { if(correct_path[i]==' ') { - correct_path = correct_path.insert(i,"\\"); + correct_path = correct_path.insert(i,1,'\\'); i++; } } - std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; + std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<"\n"; std::string command = "umount "; - command += (*it).path; + command += correct_path; int err = system(command.c_str()); if(err) { From 3d036d363b164ea2d84016f087e3247adbb29eb6 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:21:41 +0100 Subject: [PATCH 067/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7216763eec..c859a5d872 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -258,7 +258,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) i++; } } - std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<"\n"; + std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; std::string command = "umount "; command += correct_path; int err = system(command.c_str()); From f81faaf9e956f4dc134e99929a8d4291aa4b05d5 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:30:25 +0100 Subject: [PATCH 068/162] path check --- src/slic3r/GUI/RemovableDriveManager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index c859a5d872..3d77606c81 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -259,7 +259,13 @@ void RemovableDriveManager::eject_drive(const std::string &path) } } std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; - std::string command = "umount "; + + std::string command = ""; +#if __APPLE__ + command = "diskutil unmount "; +#else + command = "umount "; +#endif command += correct_path; int err = system(command.c_str()); if(err) From a6e10e8fa27b654718e622ba66933a6e4586ad51 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 13:43:28 +0100 Subject: [PATCH 069/162] comment testing lines --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 3d77606c81..0665e57dc2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -317,7 +317,7 @@ bool RemovableDriveManager::update(long time) } search_for_drives(); check_and_notify(); - eject_drive(m_current_drives.back().path); + //eject_drive(m_current_drives.back().path); return !m_current_drives.empty(); } From 1c8ca1aec15d70a4b1ed172a245b028e26948b44 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 4 Dec 2019 15:27:33 +0100 Subject: [PATCH 070/162] refactoring --- src/slic3r/GUI/RemovableDriveManager.cpp | 14 +++++++------- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 0665e57dc2..a655425fc4 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -121,6 +121,7 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } void RemovableDriveManager::register_window() { + //std::cout << "Registering for device notification\n"; /* WNDCLASSEX wndClass; @@ -137,6 +138,7 @@ void RemovableDriveManager::register_window() wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; */ + //std::cout << "Failed\n"; } #else void RemovableDriveManager::search_for_drives() @@ -191,7 +193,7 @@ void RemovableDriveManager::search_for_drives() } - std::cout << "found drives:" < callback); void print(); private: - RemovableDriveManager():m_drives_count(0){} + RemovableDriveManager():m_drives_count(0),m_last_update(0){} void search_for_drives(); void check_and_notify(); std::vector m_current_drives; std::vector> m_callbacks; size_t m_drives_count; + long m_last_update; #if _WIN32 void register_window(); #else From 63ee4e3a2f766ad3856244c42e4f28ff5828b240 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 5 Dec 2019 14:07:02 +0100 Subject: [PATCH 071/162] last path functions --- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/Plater.cpp | 2 + src/slic3r/GUI/RemovableDriveManager.cpp | 174 +++++++++++++++++++++-- src/slic3r/GUI/RemovableDriveManager.hpp | 12 +- 4 files changed, 173 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e6c92cd0a8..0d608876eb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -272,7 +272,8 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime()); + //RemovableDriveManager::get_instance().update(wxGetLocalTime()); + std::cout << RemovableDriveManager::get_instance().is_last_drive_removed() << "\n"; // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3e3827926f..b8b2f45e8b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4681,9 +4681,11 @@ void Plater::export_gcode() fs::path path = into_path(dlg.GetPath()); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = std::move(path); + RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); } if (! output_path.empty()) p->export_gcode(std::move(output_path), PrintHostJob()); + } void Plater::export_stl(bool extended, bool selection_only) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index a655425fc4..146bebc119 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -7,8 +7,11 @@ #include #include #include -DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, - 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); + +//#include +//GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, +// 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; + #else //linux includes #include @@ -26,6 +29,7 @@ namespace GUI { #if _WIN32 +//INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); @@ -84,7 +88,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) { std::string mpath = "\\\\.\\" + path; mpath = mpath.substr(0, mpath.size() - 1); - std::cout << "Ejecting " << mpath << "\n"; + //std::cout << "Ejecting " << mpath << "\n"; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { @@ -119,10 +123,24 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } return false; } +std::string RemovableDriveManager::get_drive_from_path(const std::string& path) +{ + int letter = PathGetDriveNumberA(path.c_str()); + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + char drive = (*it).path[0]; + if (drive == ('A' + letter)) + return (*it).path; + } + return ""; +} void RemovableDriveManager::register_window() { - //std::cout << "Registering for device notification\n"; /* + std::cout << "Registering for device notification\n"; + + + WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); @@ -134,12 +152,109 @@ void RemovableDriveManager::register_window() wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192)); wndClass.hCursor = LoadCursor(0, IDC_ARROW); - wndClass.lpszClassName = L"SlicerWindowClass"; + wndClass.lpszClassName = L"PrusaSlicer_aux_class"; wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; - */ - //std::cout << "Failed\n"; + + HINSTANCE hInstanceExe = GetModuleHandle(NULL); + + HWND hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE | WS_EX_APPWINDOW, + L"PrusaSlicer_aux_class", + L"PrusaSlicer_aux_wnd", + WS_OVERLAPPEDWINDOW, // style + CW_USEDEFAULT, 0, + 640, 480, + NULL, NULL, + hInstanceExe, + NULL); +*/ } +/* +INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT lRet = 1; + static HDEVNOTIFY hDeviceNotify; + static HWND hEditWnd; + static ULONGLONG msgCount = 0; + + switch (message) + { + case WM_CREATE: + + + DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; + + ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); + NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + NotificationFilter.dbcc_classguid = WceusbshGUID; + + hDeviceNotify = RegisterDeviceNotification( + hWnd, // events recipient + &NotificationFilter, // type of device + DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle + ); + break; + + + + case WM_DEVICECHANGE: + { + std::cout << "WM_DEVICECHANGE\n"; + /* + // This is the actual message from the interface via Windows messaging. + // This code includes some additional decoding for this particular device type + // and some common validation checks. + // + // Note that not all devices utilize these optional parameters in the same + // way. Refer to the extended information for your particular device type + // specified by your GUID. + // + PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; + TCHAR strBuff[256]; + + // Output some messages to the window. + switch (wParam) + { + case DBT_DEVICEARRIVAL: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount); + break; + case DBT_DEVICEREMOVECOMPLETE: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount); + break; + case DBT_DEVNODES_CHANGED: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount); + break; + default: + msgCount++; + StringCchPrintf( + strBuff, 256, + TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"), + msgCount, wParam); + break; + } + OutputMessage(hEditWnd, wParam, (LPARAM)strBuff); + / + } + break; + default: + // Send all other messages on to the default windows handler. + lRet = DefWindowProc(hWnd, message, wParam, lParam); + break; + } + return lRet; +} +*/ #else void RemovableDriveManager::search_for_drives() { @@ -294,6 +409,16 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } return false; } +std::string RemovableDriveManager::get_drive_from_path(const std::string& path) +{ + //check if same filesystem + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + if (compare_filesystem_id(path, (*it).path)) + return (*it).path; + } + return ""; +} #endif bool RemovableDriveManager::update(long time) { @@ -301,7 +426,7 @@ bool RemovableDriveManager::update(long time) { //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 - register_window(); + //register_window(); #endif } if(time != 0) //time = 0 is forced update @@ -338,11 +463,9 @@ std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { -//#if _WIN32 -// return m_current_drives.back().path + "\\"; -//#else + if (m_last_save_path != "") + return m_last_save_path; return m_current_drives.back().path; -//#endif } return ""; } @@ -356,9 +479,12 @@ void RemovableDriveManager::check_and_notify() if(m_drives_count != m_current_drives.size()) { //std::cout<<" vs "<< m_current_drives.size(); - for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) + if(m_drives_count > m_current_drives.size()) { - (*it)(); + for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) + { + (*it)(); + } } m_drives_count = m_current_drives.size(); } @@ -368,6 +494,26 @@ void RemovableDriveManager::add_callback(std::function callback) { m_callbacks.push_back(callback); } +void RemovableDriveManager::set_last_save_path(const std::string& path) +{ + std::string last_drive = get_drive_from_path(path); + if(last_drive != "") + { + m_last_save_path = last_drive; + } +} +bool RemovableDriveManager::is_last_drive_removed() +{ + if(m_last_save_path == "") + { + return true; + } + return !is_drive_mounted(m_last_save_path); +} +void RemovableDriveManager::reset_last_save_path() +{ + m_last_save_path = ""; +} void RemovableDriveManager::print() { std::cout << "notified\n"; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c65a7fe625..be5ae5968e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,24 +24,30 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - bool update(long time = 0); //time = 0 is forced update + bool update(long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); - void add_callback(std::function callback); + void add_callback(std::function callback); // callback will notify every drive removal. to see if it was last used drive call is_last_drive_removed() + void set_last_save_path(const std::string &path); + bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); + void reset_last_save_path(); void print(); private: - RemovableDriveManager():m_drives_count(0),m_last_update(0){} + RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} void search_for_drives(); void check_and_notify(); + std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" std::vector m_current_drives; std::vector> m_callbacks; size_t m_drives_count; long m_last_update; + std::string m_last_save_path; #if _WIN32 void register_window(); + //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); From 66f203379cb7437a69e04cb6d88d24ee40a014df Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 5 Dec 2019 16:22:54 +0100 Subject: [PATCH 072/162] last save path --- src/slic3r/GUI/GUI_App.cpp | 7 ++++--- src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++++++++-- src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 0d608876eb..28812dcf43 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -272,9 +272,10 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - //RemovableDriveManager::get_instance().update(wxGetLocalTime()); - std::cout << RemovableDriveManager::get_instance().is_last_drive_removed() << "\n"; - + + RemovableDriveManager::get_instance().update(wxGetLocalTime()); + + // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. // The extra CallAfter() is needed because of Mac, where this is the only way diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 146bebc119..e94ea6918a 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -420,11 +420,11 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) return ""; } #endif -bool RemovableDriveManager::update(long time) +bool RemovableDriveManager::update(const long time) { if(m_last_update == 0) { - //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); + add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 //register_window(); #endif @@ -510,12 +510,18 @@ bool RemovableDriveManager::is_last_drive_removed() } return !is_drive_mounted(m_last_save_path); } +bool RemovableDriveManager::is_last_drive_removed_with_update(const long time) +{ + update(time); + return is_last_drive_removed(); +} void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } void RemovableDriveManager::print() { + //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; std::cout << "notified\n"; } }}//namespace Slicer::Gui:: \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index be5ae5968e..906667244b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,7 +24,7 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. - bool update(long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_drive_path(); @@ -33,6 +33,7 @@ public: void add_callback(std::function callback); // callback will notify every drive removal. to see if it was last used drive call is_last_drive_removed() void set_last_save_path(const std::string &path); bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); + bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); void print(); private: From 6396ec571a0c70367c917efaf2b662b300a2723c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 6 Dec 2019 13:17:36 +0100 Subject: [PATCH 073/162] callback only for used device --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index e94ea6918a..6581d53614 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -479,7 +479,7 @@ void RemovableDriveManager::check_and_notify() if(m_drives_count != m_current_drives.size()) { //std::cout<<" vs "<< m_current_drives.size(); - if(m_drives_count > m_current_drives.size()) + if(m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 906667244b..741b4424ab 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -30,7 +30,7 @@ public: std::string get_last_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); - void add_callback(std::function callback); // callback will notify every drive removal. to see if it was last used drive call is_last_drive_removed() + void add_callback(std::function callback); // callback will notify only if device with last save path was removed void set_last_save_path(const std::string &path); bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() From b386eb45dccc3d951940ed32e6cb6ff945dfa773 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 6 Dec 2019 13:21:44 +0100 Subject: [PATCH 074/162] erase callbacks --- src/slic3r/GUI/RemovableDriveManager.cpp | 4 ++++ src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 6581d53614..1fbc33fc57 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -494,6 +494,10 @@ void RemovableDriveManager::add_callback(std::function callback) { m_callbacks.push_back(callback); } +void RemovableDriveManager::erase_callbacks() +{ + m_callbacks.clear(); +} void RemovableDriveManager::set_last_save_path(const std::string& path) { std::string last_drive = get_drive_from_path(path); diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 741b4424ab..8d9e65c47e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -31,6 +31,7 @@ public: std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); void add_callback(std::function callback); // callback will notify only if device with last save path was removed + void erase_callbacks(); // erases all callbacks added by add_callback() void set_last_save_path(const std::string &path); bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() From 8f069e2d473ddb98d4adb7e3d094e2c0fae5b73c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 6 Dec 2019 16:51:04 +0100 Subject: [PATCH 075/162] windows registration for device notif(thru hidden app) - windows doesnt need update now --- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/RemovableDriveManager.cpp | 108 ++++++++--------------- src/slic3r/GUI/RemovableDriveManager.hpp | 2 + 3 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 28812dcf43..72c84ba799 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -273,7 +273,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime()); + //RemovableDriveManager::get_instance().update(wxGetLocalTime()); // Preset updating & Configwizard are done after the above initializations, @@ -303,6 +303,7 @@ bool GUI_App::on_init_inner() preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); }); + RemovableDriveManager::get_instance().init(); } }); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 1fbc33fc57..5daa9eb261 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -8,9 +8,9 @@ #include #include -//#include -//GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, -// 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; +#include +GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, + 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; #else //linux includes @@ -29,7 +29,7 @@ namespace GUI { #if _WIN32 -//INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); @@ -136,13 +136,8 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) } void RemovableDriveManager::register_window() { - /* std::cout << "Registering for device notification\n"; - - - WNDCLASSEX wndClass; - wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); @@ -155,34 +150,41 @@ void RemovableDriveManager::register_window() wndClass.lpszClassName = L"PrusaSlicer_aux_class"; wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; - - HINSTANCE hInstanceExe = GetModuleHandle(NULL); + if(!RegisterClassEx(&wndClass)) + { + DWORD err = GetLastError(); + return; + } HWND hWnd = CreateWindowEx( - WS_EX_CLIENTEDGE | WS_EX_APPWINDOW, + WS_EX_NOACTIVATE, L"PrusaSlicer_aux_class", L"PrusaSlicer_aux_wnd", - WS_OVERLAPPEDWINDOW, // style + WS_DISABLED, // style CW_USEDEFAULT, 0, 640, 480, NULL, NULL, - hInstanceExe, + GetModuleHandle(NULL), NULL); -*/ + if(hWnd == NULL) + { + DWORD err = GetLastError(); + } + //ShowWindow(hWnd, SW_SHOWNORMAL); + UpdateWindow(hWnd); } -/* + INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT lRet = 1; static HDEVNOTIFY hDeviceNotify; + static HWND hEditWnd; static ULONGLONG msgCount = 0; switch (message) { case WM_CREATE: - - DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); @@ -196,55 +198,13 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle ); break; - - - case WM_DEVICECHANGE: { - std::cout << "WM_DEVICECHANGE\n"; - /* - // This is the actual message from the interface via Windows messaging. - // This code includes some additional decoding for this particular device type - // and some common validation checks. - // - // Note that not all devices utilize these optional parameters in the same - // way. Refer to the extended information for your particular device type - // specified by your GUID. - // - PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; - TCHAR strBuff[256]; - - // Output some messages to the window. - switch (wParam) + if(wParam == DBT_DEVICEREMOVECOMPLETE) { - case DBT_DEVICEARRIVAL: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount); - break; - case DBT_DEVICEREMOVECOMPLETE: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount); - break; - case DBT_DEVNODES_CHANGED: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount); - break; - default: - msgCount++; - StringCchPrintf( - strBuff, 256, - TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"), - msgCount, wParam); - break; + std::cout << "WM_DEVICECHANGE\n"; + RemovableDriveManager::get_instance().on_drive_removed_callback(); } - OutputMessage(hEditWnd, wParam, (LPARAM)strBuff); - / } break; default: @@ -254,7 +214,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP } return lRet; } -*/ + #else void RemovableDriveManager::search_for_drives() { @@ -420,15 +380,16 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) return ""; } #endif +void RemovableDriveManager::init() +{ + add_callback([](void) { RemovableDriveManager::get_instance().print(); }); +#if _WIN32 + register_window(); +#endif + update(); +} bool RemovableDriveManager::update(const long time) { - if(m_last_update == 0) - { - add_callback([](void) { RemovableDriveManager::get_instance().print(); }); -#if _WIN32 - //register_window(); -#endif - } if(time != 0) //time = 0 is forced update { long diff = m_last_update - time; @@ -442,7 +403,6 @@ bool RemovableDriveManager::update(const long time) } search_for_drives(); check_and_notify(); - //eject_drive(m_current_drives.back().path); return !m_current_drives.empty(); } @@ -523,6 +483,10 @@ void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } +void RemovableDriveManager::on_drive_removed_callback() +{ + update(); +} void RemovableDriveManager::print() { //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 8d9e65c47e..210d89477b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -24,6 +24,7 @@ public: void operator=(RemovableDriveManager const&) = delete; //update() searches for removable devices, returns false if empty. + void init(); bool update(const long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); @@ -36,6 +37,7 @@ public: bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); + void on_drive_removed_callback(); void print(); private: RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} From 91c358fe237e3bd0232c661ca99b813472cb2719 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 9 Dec 2019 15:33:10 +0100 Subject: [PATCH 076/162] osx device unmount callback - not sure if will build --- src/slic3r/CMakeLists.txt | 1 + src/slic3r/GUI/RemovableDriveManager.cpp | 11 ++--- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +- src/slic3r/GUI/RemovableDriveManager.mm | 51 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/slic3r/GUI/RemovableDriveManager.mm diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 2d7b99b73d..246f1365b0 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -169,6 +169,7 @@ if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm Utils/MacDarkMode.mm + GUI/RemovableDriveManager.mm ) endif () diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 5daa9eb261..166728e68b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -203,7 +203,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP if(wParam == DBT_DEVICEREMOVECOMPLETE) { std::cout << "WM_DEVICECHANGE\n"; - RemovableDriveManager::get_instance().on_drive_removed_callback(); + RemovableDriveManager::get_instance().update(); } } break; @@ -219,6 +219,10 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP void RemovableDriveManager::search_for_drives() { +#if __APPLE__ + list_devices(); +#endif + m_current_drives.clear(); m_current_drives.reserve(26); @@ -483,10 +487,7 @@ void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } -void RemovableDriveManager::on_drive_removed_callback() -{ - update(); -} + void RemovableDriveManager::print() { //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 210d89477b..501c16b71a 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -37,7 +37,6 @@ public: bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); - void on_drive_removed_callback(); void print(); private: RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} @@ -52,6 +51,9 @@ private: #if _WIN32 void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +#elif __APPLE__ + void register_window(); + void list_devices(); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); diff --git a/src/slic3r/GUI/RemovableDriveManager.mm b/src/slic3r/GUI/RemovableDriveManager.mm new file mode 100644 index 0000000000..a1358625fc --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManager.mm @@ -0,0 +1,51 @@ +#import "RemovableDriveManager.hpp" + +@implementation RemovableDriveManager + +namespace Slic3r { +namespace GUI { + +void RemovableDriveManager::register_window() +{ + //[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumesChanged:) name:NSWorkspaceDidMountNotification object: nil]; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; +} + +-(void) on_device_unmount: (NSNotification*) notification +{ + NSLog(@"on device change"); + RemovableDriveManager::get_instance().update(); +} + +-(void) RemovableDriveManager::list_devices() +{ + NSLog(@"---"); + NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; + for (NSString* volumePath in listOfMedia) + { + NSLog(@"@", volumePath); + } + NSLog(@"--"); + //removable here means CD not USB :/ + NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; + NSLog(@"%@", listOfMedia); + + for (NSString* volumePath in listOfMedia) + { + BOOL isRemovable = NO; + BOOL isWritable = NO; + BOOL isUnmountable = NO; + NSString* description = [NSString string]; + NSString* type = [NSString string]; + + BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath + isRemovable:&isRemovable + isWritable:&isWritable + isUnmountable:&isUnmountable + description:&description + type:&type]; + NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); + } +} + +}}//namespace Slicer::GUI \ No newline at end of file From 0861b2ec591161355890779058b91a23cb7580c1 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 9 Dec 2019 17:12:22 +0100 Subject: [PATCH 077/162] init call --- src/slic3r/GUI/GUI_App.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 72c84ba799..e13701f61d 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -262,6 +262,8 @@ bool GUI_App::on_init_inner() m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); + RemovableDriveManager::get_instance().init(); + Bind(wxEVT_IDLE, [this](wxIdleEvent& event) { if (! plater_) @@ -303,7 +305,7 @@ bool GUI_App::on_init_inner() preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); }); - RemovableDriveManager::get_instance().init(); + } }); From e0a12342da33ea2e79b06777c5579294094353ed Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 10 Dec 2019 10:08:57 +0100 Subject: [PATCH 078/162] macos mm files --- src/slic3r/CMakeLists.txt | 3 +- src/slic3r/GUI/RemovableDriveManager.hpp | 3 +- src/slic3r/GUI/RemovableDriveManagerMM.h | 9 ++++++ ...eManager.mm => RemovableDriveManagerMM.mm} | 29 +++++++++++++++---- 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 src/slic3r/GUI/RemovableDriveManagerMM.h rename src/slic3r/GUI/{RemovableDriveManager.mm => RemovableDriveManagerMM.mm} (86%) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 246f1365b0..a06a8cf1d1 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -169,7 +169,8 @@ if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm Utils/MacDarkMode.mm - GUI/RemovableDriveManager.mm + GUI/RemovableDriveManagerMM.mm + GUI/RemovableDriveManagerMM.h ) endif () diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 501c16b71a..04bbe48b5d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -52,8 +52,9 @@ private: void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #elif __APPLE__ + void *m_rdmmm; void register_window(); - void list_devices(); + //void list_devices(); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h new file mode 100644 index 0000000000..8f783c2d2a --- /dev/null +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -0,0 +1,9 @@ +#import + +@interface RemovableDriveManagerMM : NSObject + +-(instancetype) init; +-(void) add_unmount_observer; +-(void) on_device_unmount: (NSNotification*) notification; + +@end \ No newline at end of file diff --git a/src/slic3r/GUI/RemovableDriveManager.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm similarity index 86% rename from src/slic3r/GUI/RemovableDriveManager.mm rename to src/slic3r/GUI/RemovableDriveManagerMM.mm index a1358625fc..e4e324654e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -1,22 +1,39 @@ #import "RemovableDriveManager.hpp" -@implementation RemovableDriveManager +#import + +@implementation RemovableDriveManagerMM namespace Slic3r { namespace GUI { -void RemovableDriveManager::register_window() +-(instancetype) init { - //[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumesChanged:) name:NSWorkspaceDidMountNotification object: nil]; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; + self = [super init]; + if(self) + { + [self add_unmount_observer] + } + return self; } - -(void) on_device_unmount: (NSNotification*) notification { NSLog(@"on device change"); RemovableDriveManager::get_instance().update(); } +-(void) add_unmount_observer +{ + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; +} +void RemovableDriveManager::register_window() +{ + m_rdmmm = nullptr; + m_rdmmm = [[RemovableDriveManagerMM alloc] init]; +} + + +/* -(void) RemovableDriveManager::list_devices() { NSLog(@"---"); @@ -47,5 +64,5 @@ void RemovableDriveManager::register_window() NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); } } - +*/ }}//namespace Slicer::GUI \ No newline at end of file From c3653589f6cec74a9a4241c9de55e28c178cd6d6 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Tue, 10 Dec 2019 11:17:12 +0100 Subject: [PATCH 079/162] macos implementation --- src/slic3r/GUI/RemovableDriveManager.cpp | 8 +++++--- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +++- src/slic3r/GUI/RemovableDriveManagerMM.mm | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 166728e68b..8145c90760 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -218,11 +218,11 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP #else void RemovableDriveManager::search_for_drives() { - + /* #if __APPLE__ list_devices(); #endif - +*/ m_current_drives.clear(); m_current_drives.reserve(26); @@ -389,6 +389,8 @@ void RemovableDriveManager::init() add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); +#elif __APPLE__ + register_window(); #endif update(); } @@ -493,4 +495,4 @@ void RemovableDriveManager::print() //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; std::cout << "notified\n"; } -}}//namespace Slicer::Gui:: \ No newline at end of file +}}//namespace Slicer::Gui:: diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 04bbe48b5d..c4f55029b7 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -55,10 +55,12 @@ private: void *m_rdmmm; void register_window(); //void list_devices(); + void search_path(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #else void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; }} -#endif \ No newline at end of file +#endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index e4e324654e..99abd73860 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -1,37 +1,38 @@ #import "RemovableDriveManager.hpp" - +#import "RemovableDriveManagerMM.h" #import @implementation RemovableDriveManagerMM -namespace Slic3r { -namespace GUI { + -(instancetype) init { self = [super init]; if(self) { - [self add_unmount_observer] + [self add_unmount_observer]; } return self; } -(void) on_device_unmount: (NSNotification*) notification { NSLog(@"on device change"); - RemovableDriveManager::get_instance().update(); + Slic3r::GUI::RemovableDriveManager::get_instance().update(); } -(void) add_unmount_observer { + NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; } - +namespace Slic3r { +namespace GUI { void RemovableDriveManager::register_window() { m_rdmmm = nullptr; m_rdmmm = [[RemovableDriveManagerMM alloc] init]; } - +}}//namespace Slicer::GUI /* -(void) RemovableDriveManager::list_devices() @@ -65,4 +66,5 @@ void RemovableDriveManager::register_window() } } */ -}}//namespace Slicer::GUI \ No newline at end of file + +@end From c37128ad638f99c5b090cce5427e12bcbf81af94 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Tue, 10 Dec 2019 11:35:39 +0100 Subject: [PATCH 080/162] macos list devices --- src/slic3r/GUI/RemovableDriveManager.cpp | 4 +- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +- src/slic3r/GUI/RemovableDriveManagerMM.h | 4 +- src/slic3r/GUI/RemovableDriveManagerMM.mm | 65 +++++++++++++---------- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 8145c90760..50e2b6359c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -218,11 +218,11 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP #else void RemovableDriveManager::search_for_drives() { - /* + #if __APPLE__ list_devices(); #endif -*/ + m_current_drives.clear(); m_current_drives.reserve(26); diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c4f55029b7..7109bbd070 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -39,7 +39,7 @@ public: void reset_last_save_path(); void print(); private: - RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""){} + RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(nullptr){} void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" @@ -54,7 +54,7 @@ private: #elif __APPLE__ void *m_rdmmm; void register_window(); - //void list_devices(); + void list_devices(); void search_path(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #else diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h index 8f783c2d2a..4a5fa2515e 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.h +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -5,5 +5,5 @@ -(instancetype) init; -(void) add_unmount_observer; -(void) on_device_unmount: (NSNotification*) notification; - -@end \ No newline at end of file +-(void) list_dev; +@end diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 99abd73860..7e8b56c59b 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -25,6 +25,36 @@ NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; } +-(void) list_dev +{ + NSLog(@"---"); + NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; + for (NSString* volumePath in devices) + { + NSLog(@"@", volumePath); + } + NSLog(@"--"); + //removable here means CD not USB :/ + NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; + NSLog(@"%@", listOfMedia); + + for (NSString* volumePath in listOfMedia) + { + BOOL isRemovable = NO; + BOOL isWritable = NO; + BOOL isUnmountable = NO; + NSString* description = [NSString string]; + NSString* type = [NSString string]; + + BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath + isRemovable:&isRemovable + isWritable:&isWritable + isUnmountable:&isUnmountable + description:&description + type:&type]; + NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); + } +} namespace Slic3r { namespace GUI { void RemovableDriveManager::register_window() @@ -32,39 +62,16 @@ void RemovableDriveManager::register_window() m_rdmmm = nullptr; m_rdmmm = [[RemovableDriveManagerMM alloc] init]; } +void RemovableDriveManager::list_devices() +{ + if(m_rdmmm == nullptr) + return; + [m_rdmmm list_dev]; +} }}//namespace Slicer::GUI /* --(void) RemovableDriveManager::list_devices() -{ - NSLog(@"---"); - NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; - for (NSString* volumePath in listOfMedia) - { - NSLog(@"@", volumePath); - } - NSLog(@"--"); - //removable here means CD not USB :/ - NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; - NSLog(@"%@", listOfMedia); - for (NSString* volumePath in listOfMedia) - { - BOOL isRemovable = NO; - BOOL isWritable = NO; - BOOL isUnmountable = NO; - NSString* description = [NSString string]; - NSString* type = [NSString string]; - - BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath - isRemovable:&isRemovable - isWritable:&isWritable - isUnmountable:&isUnmountable - description:&description - type:&type]; - NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); - } -} */ @end From a259058845e50d635883e16cf86d0988c31a76bd Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 10 Dec 2019 14:10:47 +0100 Subject: [PATCH 081/162] macos better wrapper --- src/slic3r/GUI/RemovableDriveManager.cpp | 50 +++++++++-------- src/slic3r/GUI/RemovableDriveManager.hpp | 33 ++++++++--- src/slic3r/GUI/RemovableDriveManagerMM.h | 2 +- src/slic3r/GUI/RemovableDriveManagerMM.mm | 68 +++++++++++------------ 4 files changed, 87 insertions(+), 66 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 50e2b6359c..763113ea2c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -220,9 +220,11 @@ void RemovableDriveManager::search_for_drives() { #if __APPLE__ - list_devices(); -#endif - + if(m_rdmmm) + { + m_rdmmm->list_devices(); + } +#else m_current_drives.clear(); m_current_drives.reserve(26); @@ -273,6 +275,7 @@ void RemovableDriveManager::search_for_drives() } //std::cout << "found drives:" <pw_name == username) - { - std::string name = basename(globbuf.gl_pathv[i]); - m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); - } - } - } + } }else { @@ -310,7 +296,27 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin globfree(&globbuf); } - +void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path) +{ + //if not same file system - could be removable drive + if(!compare_filesystem_id(globbuf.gl_pathv[i], parent_path)) + { + //user id + struct stat buf; + stat(globbuf.gl_pathv[i],&buf); + uid_t uid = buf.st_uid; + std::string username(std::getenv("USER")); + struct passwd *pw = getpwuid(uid); + if(pw != 0) + { + if(pw->pw_name == username) + { + std::string name = basename(globbuf.gl_pathv[i]); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); + } + } + } +} bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, const std::string &path_b) { struct stat buf; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 7109bbd070..202680328e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -39,7 +39,11 @@ public: void reset_last_save_path(); void print(); private: - RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(nullptr){} +#if __APPLE__ + RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(new RemovableDriveManagerMM()){} +#else + RemovableDriveManager() : m_drives_count(0), m_last_update(0), m_last_save_path(""){} +#endif void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" @@ -51,16 +55,27 @@ private: #if _WIN32 void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -#elif __APPLE__ - void *m_rdmmm; - void register_window(); - void list_devices(); - void search_path(const std::string &path, const std::string &parent_path); - bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #else - void search_path(const std::string &path, const std::string &parent_path); - bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); +#if __APPLE__ + RemovableDriveManagerMM * m_rdmmm; + #endif + void search_path(const std::string &path, const std::string &parent_path); + void inspect_file(const std::string &path, const std::string &parent_path); + bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; +#if __APPLE__ +class RemovableDriveManagerMM +{ +public: + RemovableDriveManagerMM(); + ~RemovableDriveManagerMM(); + register_window(); + list_devices(); +private: + RemovableDriveManagerMMImpl *m_imp; + friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); +}; +#endif }} #endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h index 4a5fa2515e..2999415454 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.h +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -5,5 +5,5 @@ -(instancetype) init; -(void) add_unmount_observer; -(void) on_device_unmount: (NSNotification*) notification; --(void) list_dev; +-(NSArray*) list_dev; @end diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 7e8b56c59b..25fa6da091 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -10,8 +10,7 @@ { self = [super init]; if(self) - { - [self add_unmount_observer]; + { } return self; } @@ -25,48 +24,49 @@ NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; } --(void) list_dev +-(NSArray*) list_dev { - NSLog(@"---"); NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; for (NSString* volumePath in devices) { - NSLog(@"@", volumePath); - } - NSLog(@"--"); - //removable here means CD not USB :/ - NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; - NSLog(@"%@", listOfMedia); + NSLog(@"%@", volumePath); + } + return devices; - for (NSString* volumePath in listOfMedia) - { - BOOL isRemovable = NO; - BOOL isWritable = NO; - BOOL isUnmountable = NO; - NSString* description = [NSString string]; - NSString* type = [NSString string]; - - BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath - isRemovable:&isRemovable - isWritable:&isWritable - isUnmountable:&isUnmountable - description:&description - type:&type]; - NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); - } } namespace Slic3r { namespace GUI { -void RemovableDriveManager::register_window() -{ - m_rdmmm = nullptr; - m_rdmmm = [[RemovableDriveManagerMM alloc] init]; +struct RemovableDriveManagerMMImpl{ + RemovableDriveManagerMM * wrap; } -void RemovableDriveManager::list_devices() +RemovableDriveManagerMM():impl(new RemovableDriveManagerMMImpl){ + impl->wrap = [[RemovableDriveManagerMM alloc] init]; +} +RemovableDriveManagerMM::~RemovableDriveManagerMM() { - if(m_rdmmm == nullptr) - return; - [m_rdmmm list_dev]; + if(impl) + { + [impl->wrap release]; + } +} +void RDMMMWrapper::register_window() +{ + if(impl->wrap) + { + [impl->wrap add_unmount_observer]; + } +} +void RDMMMWrapper::list_devices() +{ + if(impl->wrap) + { + NSArray* devices = [impl->wrap list_dev]; + for (NSString* volumePath in devices) + { + NSLog(@"%@", volumePath); + Slic3r::GUI::RemovableDriveManager::get_instance().inspect_file(std::string([volumePath UTF8String]), "/Volumes"); + } + } } }}//namespace Slicer::GUI From c47fda39f1fb47fa77ff5e575bc4123597fb4c1a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 10 Dec 2019 17:31:27 +0100 Subject: [PATCH 082/162] Implemented "Disconnect" button --- src/slic3r/GUI/Plater.cpp | 41 ++++++++++++++++++++++++++++++++------- src/slic3r/GUI/Plater.hpp | 1 + 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b8b2f45e8b..7b5cef4ca4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -700,6 +700,7 @@ struct Sidebar::priv wxButton *btn_export_gcode; wxButton *btn_reslice; wxButton *btn_send_gcode; + ScalableButton *btn_disconnect; priv(Plater *plater) : plater(plater) {} ~priv(); @@ -848,22 +849,39 @@ Sidebar::Sidebar(Plater *parent) // Buttons underneath the scrolled area - auto init_btn = [this](wxButton **btn, wxString label) { + auto init_btn = [this](wxButton **btn, wxString label, const std::string icon_name = "", wxString tooltip = wxEmptyString) { *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); (*btn)->SetFont(wxGetApp().bold_font()); + (*btn)->SetToolTip(tooltip); + + if (!icon_name.empty()) + (*btn)->SetBitmap(create_scaled_bitmap(this, icon_name)); }; - init_btn(&p->btn_send_gcode, _(L("Send to printer"))); + init_btn(&p->btn_send_gcode, /*_(L("Send to printer"))*/"", "export_gcode", _(L("Send to printer"))); p->btn_send_gcode->Hide(); init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots); init_btn(&p->btn_reslice, _(L("Slice now"))); + + p->btn_disconnect = new ScalableButton(this, wxID_ANY, "revert_all_", "", + wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT); + p->btn_disconnect->Hide(); + p->btn_disconnect->SetToolTip(_(L("Remove device"))); + enable_buttons(false); auto *btns_sizer = new wxBoxSizer(wxVERTICAL); + + auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); + complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); + complect_btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND); + complect_btns_sizer->Add(p->btn_disconnect); + btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); - btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); - btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); + btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5); +// btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); +// btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(p->scrolled, 1, wxEXPAND); @@ -882,6 +900,9 @@ Sidebar::Sidebar(Plater *parent) p->plater->select_view_3D("Preview"); }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); + p->btn_disconnect->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { + // #dk_FIXME + }); } Sidebar::~Sidebar() {} @@ -1255,11 +1276,13 @@ void Sidebar::enable_buttons(bool enable) p->btn_reslice->Enable(enable); p->btn_export_gcode->Enable(enable); p->btn_send_gcode->Enable(enable); + p->btn_disconnect->Enable(enable); } bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); } bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); } bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); } +bool Sidebar::show_disconnect(bool show)const { return p->btn_disconnect->Show(show); } bool Sidebar::is_multifilament() { @@ -4125,20 +4148,24 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const wxWindowUpdateLocker noUpdater(sidebar); const auto prin_host_opt = config->option("print_host"); const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); + + const bool disconnect_shown = true; // #dk_FIXME // when a background processing is ON, export_btn and/or send_btn are showing if (wxGetApp().app_config->get("background_processing") == "1") { if (sidebar->show_reslice(false) | sidebar->show_export(true) | - sidebar->show_send(send_gcode_shown)) + sidebar->show_send(send_gcode_shown) | + sidebar->show_disconnect(disconnect_shown)) sidebar->Layout(); } else { if (sidebar->show_reslice(is_ready_to_slice) | sidebar->show_export(!is_ready_to_slice) | - sidebar->show_send(send_gcode_shown && !is_ready_to_slice)) + sidebar->show_send(send_gcode_shown && !is_ready_to_slice) | + sidebar->show_disconnect(disconnect_shown && !is_ready_to_slice)) sidebar->Layout(); } } @@ -4379,7 +4406,7 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab { case ActionButtonType::abReslice: p->btn_reslice->SetLabelText(label); break; case ActionButtonType::abExport: p->btn_export_gcode->SetLabelText(label); break; - case ActionButtonType::abSendGCode: p->btn_send_gcode->SetLabelText(label); break; + case ActionButtonType::abSendGCode: /*p->btn_send_gcode->SetLabelText(label);*/ break; } } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 33140c4f5d..528d652971 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -119,6 +119,7 @@ public: bool show_reslice(bool show) const; bool show_export(bool show) const; bool show_send(bool show) const; + bool show_disconnect(bool show)const; bool is_multifilament(); void update_mode(); From 95ff384e47d3d4020af1a0468616fd2f167f0d76 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 10 Dec 2019 14:41:49 +0100 Subject: [PATCH 083/162] fix --- src/slic3r/GUI/RemovableDriveManager.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 763113ea2c..c5dca1bd55 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -231,9 +231,10 @@ void RemovableDriveManager::search_for_drives() //search /media/* folder search_path("/media/*", "/media"); +/* //search /Volumes/* folder (OSX) search_path("/Volumes/*", "/Volumes"); - +*/ std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; @@ -286,7 +287,7 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin { for(size_t i = 0; i < globbuf.gl_pathc; i++) { - + inspect_file(globbuf.gl_pathv[i], parent_path); } }else { @@ -299,11 +300,11 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path) { //if not same file system - could be removable drive - if(!compare_filesystem_id(globbuf.gl_pathv[i], parent_path)) + if(!compare_filesystem_id(path, parent_path)) { //user id struct stat buf; - stat(globbuf.gl_pathv[i],&buf); + stat(path.c_str(), &buf); uid_t uid = buf.st_uid; std::string username(std::getenv("USER")); struct passwd *pw = getpwuid(uid); @@ -311,8 +312,8 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str { if(pw->pw_name == username) { - std::string name = basename(globbuf.gl_pathv[i]); - m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); + std::string name = basename(const_cast(path.c_str())); + m_current_drives.push_back(DriveData(name,path)); } } } From 9e4f470f98037860346d7902b84b0407099dba1d Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 10:16:32 +0100 Subject: [PATCH 084/162] macos better wrapper --- src/slic3r/GUI/RemovableDriveManager.hpp | 29 +++++++++++++---------- src/slic3r/GUI/RemovableDriveManagerMM.mm | 21 +++++++--------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 202680328e..cbf6f53aac 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -6,6 +6,10 @@ namespace Slic3r { namespace GUI { +class RDMMMWrapper; +#if __APPLE__ + + struct DriveData { std::string name; @@ -57,25 +61,24 @@ private: //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #else #if __APPLE__ - RemovableDriveManagerMM * m_rdmmm; + RDMMMWrapper * m_rdmmm; #endif void search_path(const std::string &path, const std::string &parent_path); void inspect_file(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); #endif }; -#if __APPLE__ -class RemovableDriveManagerMM -{ -public: - RemovableDriveManagerMM(); - ~RemovableDriveManagerMM(); - register_window(); - list_devices(); -private: - RemovableDriveManagerMMImpl *m_imp; - friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); -}; + class RDMMMWrapper + { + public: + RDMMMWrapper(); + ~RDMMMWrapper(); + void register_window(); + void list_devices(); + private: + void *m_imp; + friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); + }; #endif }} #endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 25fa6da091..269a2255b0 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -36,31 +36,28 @@ } namespace Slic3r { namespace GUI { -struct RemovableDriveManagerMMImpl{ - RemovableDriveManagerMM * wrap; +RDMMMWrapper::RDMMMWrapper():m_imp(nullptr){ + m_imp = [[RemovableDriveManagerMM alloc] init]; } -RemovableDriveManagerMM():impl(new RemovableDriveManagerMMImpl){ - impl->wrap = [[RemovableDriveManagerMM alloc] init]; -} -RemovableDriveManagerMM::~RemovableDriveManagerMM() +RDMMMWrapper::~RDMMMWrapper() { - if(impl) + if(m_imp) { - [impl->wrap release]; + [m_imp release]; } } void RDMMMWrapper::register_window() { - if(impl->wrap) + if(m_imp) { - [impl->wrap add_unmount_observer]; + [m_imp add_unmount_observer]; } } void RDMMMWrapper::list_devices() { - if(impl->wrap) + if(m_imp) { - NSArray* devices = [impl->wrap list_dev]; + NSArray* devices = [m_imp list_dev]; for (NSString* volumePath in devices) { NSLog(@"%@", volumePath); From 44b1a9cf7fe8b277e7ba61f50611feaeb46f922e Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 11:00:47 +0100 Subject: [PATCH 085/162] macos better wrapper --- src/slic3r/GUI/RemovableDriveManager.cpp | 12 ++++++- src/slic3r/GUI/RemovableDriveManager.hpp | 40 ++++++++++++----------- src/slic3r/GUI/RemovableDriveManagerMM.mm | 4 --- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index c5dca1bd55..164b6e38aa 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -391,13 +391,23 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) return ""; } #endif + +RemovableDriveManager::RemovableDriveManager(): + m_drives_count(0), + m_last_update(0), + m_last_save_path(""), +#if __APPLE__ + m_rdmmm(new RDMMMWrapper()) +#endif +{} + void RemovableDriveManager::init() { add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); #elif __APPLE__ - register_window(); + m_rdmmm->register_window(); #endif update(); } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index cbf6f53aac..a5027a5adf 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -6,9 +6,9 @@ namespace Slic3r { namespace GUI { -class RDMMMWrapper; #if __APPLE__ - +class RDMMMWrapper; +#endif struct DriveData { @@ -18,6 +18,9 @@ struct DriveData }; class RemovableDriveManager { +#if __APPLE__ +friend class RDMMMWrapper; +#endif public: static RemovableDriveManager& get_instance() { @@ -42,12 +45,9 @@ public: bool is_last_drive_removed_with_update(const long time = 0); // param as update() void reset_last_save_path(); void print(); + private: -#if __APPLE__ - RemovableDriveManager():m_drives_count(0),m_last_update(0),m_last_save_path(""),m_rdmmm(new RemovableDriveManagerMM()){} -#else - RemovableDriveManager() : m_drives_count(0), m_last_update(0), m_last_save_path(""){} -#endif + RemovableDriveManager(); void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" @@ -64,21 +64,23 @@ private: RDMMMWrapper * m_rdmmm; #endif void search_path(const std::string &path, const std::string &parent_path); - void inspect_file(const std::string &path, const std::string &parent_path); bool compare_filesystem_id(const std::string &path_a, const std::string &path_b); + void inspect_file(const std::string &path, const std::string &parent_path); #endif }; - class RDMMMWrapper - { - public: - RDMMMWrapper(); - ~RDMMMWrapper(); - void register_window(); - void list_devices(); - private: - void *m_imp; - friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); - }; + +#if __APPLE__ +class RDMMMWrapper +{ +public: + RDMMMWrapper(); + ~RDMMMWrapper(); + void register_window(); + void list_devices(); +protected: + void *m_imp; + //friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); +}; #endif }} #endif diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 269a2255b0..d32b7b278e 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -27,10 +27,6 @@ -(NSArray*) list_dev { NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; - for (NSString* volumePath in devices) - { - NSLog(@"%@", volumePath); - } return devices; } From 01f1bed0605662e8520f24c5db8c8bdac5f7eb4e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 11 Dec 2019 11:00:23 +0100 Subject: [PATCH 086/162] Added missed icon --- resources/icons/revert_all_.svg | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 resources/icons/revert_all_.svg diff --git a/resources/icons/revert_all_.svg b/resources/icons/revert_all_.svg new file mode 100644 index 0000000000..fe8de635db --- /dev/null +++ b/resources/icons/revert_all_.svg @@ -0,0 +1,9 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + + + \ No newline at end of file From f5e3750d233d1f9687fa9c906b39150df1eca609 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 12:28:51 +0100 Subject: [PATCH 087/162] eject button functionality --- src/slic3r/GUI/Plater.cpp | 19 ++++++++++++++++++- src/slic3r/GUI/Plater.hpp | 2 ++ src/slic3r/GUI/RemovableDriveManager.cpp | 22 +++++++++------------- src/slic3r/GUI/RemovableDriveManager.hpp | 8 +++++--- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7b5cef4ca4..ed60066e54 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -902,6 +902,7 @@ Sidebar::Sidebar(Plater *parent) p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); p->btn_disconnect->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { // #dk_FIXME + p->plater->eject_drive(); }); } @@ -4149,7 +4150,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const const auto prin_host_opt = config->option("print_host"); const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); - const bool disconnect_shown = true; // #dk_FIXME + const bool disconnect_shown = !(RemovableDriveManager::get_instance().is_last_drive_removed()); // #dk_FIXME // when a background processing is ON, export_btn and/or send_btn are showing if (wxGetApp().app_config->get("background_processing") == "1") @@ -4992,6 +4993,22 @@ void Plater::send_gcode() } } +void Plater::eject_drive() +{ + if (GUI::RemovableDriveManager::get_instance().update()) + { + RemovableDriveManager::get_instance().erase_callbacks(); + RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); + RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_drive_path()); + } +} +void Plater::drive_ejected_callback() +{ + p->show_action_buttons(false); +} + + + void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); } void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); } void Plater::suppress_snapshots() { p->suppress_snapshots(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 528d652971..d9a9af3763 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -202,6 +202,8 @@ public: void suppress_background_process(const bool stop_background_process) ; void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); void send_gcode(); + void eject_drive(); + void drive_ejected_callback(); void take_snapshot(const std::string &snapshot_name); void take_snapshot(const wxString &snapshot_name); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 164b6e38aa..1a964f889d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -395,9 +395,9 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) RemovableDriveManager::RemovableDriveManager(): m_drives_count(0), m_last_update(0), - m_last_save_path(""), + m_last_save_path("") #if __APPLE__ - m_rdmmm(new RDMMMWrapper()) + , m_rdmmm(new RDMMMWrapper()) #endif {} @@ -411,7 +411,7 @@ void RemovableDriveManager::init() #endif update(); } -bool RemovableDriveManager::update(const long time) +bool RemovableDriveManager::update(const long time, bool check) { if(time != 0) //time = 0 is forced update { @@ -425,7 +425,7 @@ bool RemovableDriveManager::update(const long time) } } search_for_drives(); - check_and_notify(); + if(check)check_and_notify(); return !m_current_drives.empty(); } @@ -444,13 +444,7 @@ bool RemovableDriveManager::is_drive_mounted(const std::string &path) std::string RemovableDriveManager::get_last_drive_path() { - if (!m_current_drives.empty()) - { - if (m_last_save_path != "") - return m_last_save_path; - return m_current_drives.back().path; - } - return ""; + return m_last_save_path; } std::vector RemovableDriveManager::get_all_drives() { @@ -495,11 +489,13 @@ bool RemovableDriveManager::is_last_drive_removed() { return true; } - return !is_drive_mounted(m_last_save_path); + bool r = !is_drive_mounted(m_last_save_path); + if (r) reset_last_save_path(); + return r; } bool RemovableDriveManager::is_last_drive_removed_with_update(const long time) { - update(time); + update(time, false); return is_last_drive_removed(); } void RemovableDriveManager::reset_last_save_path() diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index a5027a5adf..f412940010 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -32,7 +32,7 @@ public: //update() searches for removable devices, returns false if empty. void init(); - bool update(const long time = 0); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0, bool check = true); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_drive_path(); @@ -41,9 +41,8 @@ public: void add_callback(std::function callback); // callback will notify only if device with last save path was removed void erase_callbacks(); // erases all callbacks added by add_callback() void set_last_save_path(const std::string &path); - bool is_last_drive_removed(); //if we dont need info about this drive, call reset_last_save_path(); + bool is_last_drive_removed(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() - void reset_last_save_path(); void print(); private: @@ -51,11 +50,14 @@ private: void search_for_drives(); void check_and_notify(); std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" + void reset_last_save_path(); + std::vector m_current_drives; std::vector> m_callbacks; size_t m_drives_count; long m_last_update; std::string m_last_save_path; + #if _WIN32 void register_window(); //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); From 8f0eef8f36683a17b1749f52784efc7bbd2f576d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 14:53:28 +0100 Subject: [PATCH 088/162] eject button functionality --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 +++--- src/slic3r/GUI/RemovableDriveManager.cpp | 24 +++++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.hpp | 5 +++-- src/slic3r/GUI/RemovableDriveManagerMM.mm | 2 +- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e13701f61d..786a5901e5 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -275,7 +275,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - //RemovableDriveManager::get_instance().update(wxGetLocalTime()); + RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ed60066e54..7edf657be4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4694,7 +4694,7 @@ void Plater::export_gcode() { if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) { - start_dir = RemovableDriveManager::get_instance().get_last_drive_path(); + start_dir = RemovableDriveManager::get_instance().get_drive_path(); } } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), @@ -4995,11 +4995,11 @@ void Plater::send_gcode() void Plater::eject_drive() { - if (GUI::RemovableDriveManager::get_instance().update()) + if (GUI::RemovableDriveManager::get_instance().update(0, true)) { RemovableDriveManager::get_instance().erase_callbacks(); RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); - RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_drive_path()); + RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); } } void Plater::drive_ejected_callback() diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 1a964f889d..49bf59e11f 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -198,15 +198,16 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle ); break; + /* case WM_DEVICECHANGE: { if(wParam == DBT_DEVICEREMOVECOMPLETE) { - std::cout << "WM_DEVICECHANGE\n"; - RemovableDriveManager::get_instance().update(); +- RemovableDriveManager::get_instance().update(0, true); } } break; + */ default: // Send all other messages on to the default windows handler. lRet = DefWindowProc(hWnd, message, wParam, lParam); @@ -403,7 +404,7 @@ RemovableDriveManager::RemovableDriveManager(): void RemovableDriveManager::init() { - add_callback([](void) { RemovableDriveManager::get_instance().print(); }); + //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 register_window(); #elif __APPLE__ @@ -441,8 +442,18 @@ bool RemovableDriveManager::is_drive_mounted(const std::string &path) } return false; } - -std::string RemovableDriveManager::get_last_drive_path() +std::string RemovableDriveManager::get_drive_path() +{ + if (m_current_drives.size() == 0) + { + reset_last_save_path(); + return ""; + } + if (m_last_save_path != "") + return m_last_save_path; + return m_current_drives.back().path; +} +std::string RemovableDriveManager::get_last_save_path() { return m_last_save_path; } @@ -456,7 +467,7 @@ void RemovableDriveManager::check_and_notify() if(m_drives_count != m_current_drives.size()) { //std::cout<<" vs "<< m_current_drives.size(); - if(m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) + if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { @@ -485,6 +496,7 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) } bool RemovableDriveManager::is_last_drive_removed() { + m_drives_count = m_current_drives.size(); if(m_last_save_path == "") { return true; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index f412940010..49df414827 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -32,10 +32,11 @@ public: //update() searches for removable devices, returns false if empty. void init(); - bool update(const long time = 0, bool check = true); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0, bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); - std::string get_last_drive_path(); + std::string get_last_save_path(); + std::string get_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); void add_callback(std::function callback); // callback will notify only if device with last save path was removed diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index d32b7b278e..7a1108541a 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -17,7 +17,7 @@ -(void) on_device_unmount: (NSNotification*) notification { NSLog(@"on device change"); - Slic3r::GUI::RemovableDriveManager::get_instance().update(); + Slic3r::GUI::RemovableDriveManager::get_instance().update(0,true); } -(void) add_unmount_observer { From a01eec34f9f1cc1196187b6dba7a47afebd9e2bb Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 15:02:20 +0100 Subject: [PATCH 089/162] eject button functionality --- src/slic3r/GUI/Plater.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7edf657be4..8a96ac4d42 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4709,7 +4709,9 @@ void Plater::export_gcode() fs::path path = into_path(dlg.GetPath()); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = std::move(path); - RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); + } if (! output_path.empty()) p->export_gcode(std::move(output_path), PrintHostJob()); From b267e986fb67282017f6f391c7cab9b915c4df0f Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 17:02:12 +0100 Subject: [PATCH 090/162] eject button functionality --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 786a5901e5..b83ecbedc8 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -275,7 +275,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); + //RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 49bf59e11f..dc8469d9a2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -96,14 +96,16 @@ void RemovableDriveManager::eject_drive(const std::string &path) return; } DWORD deviceControlRetVal(0); + DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); - CloseHandle(handle); if (error == 0) { + CloseHandle(handle); std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; return; } - + CloseHandle(handle); m_current_drives.erase(it); break; @@ -198,7 +200,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle ); break; - /* + case WM_DEVICECHANGE: { if(wParam == DBT_DEVICEREMOVECOMPLETE) @@ -207,7 +209,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP } } break; - */ + default: // Send all other messages on to the default windows handler. lRet = DefWindowProc(hWnd, message, wParam, lParam); From 12cb9a81439e51127f2517d3767fca8ce2ed1052 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 16:59:26 +0100 Subject: [PATCH 091/162] macos eject --- src/slic3r/GUI/RemovableDriveManager.cpp | 5 +++++ src/slic3r/GUI/RemovableDriveManager.hpp | 1 + src/slic3r/GUI/RemovableDriveManagerMM.mm | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index dc8469d9a2..afe5ee7393 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -427,6 +427,10 @@ bool RemovableDriveManager::update(const long time, bool check) return false; // return value shouldnt matter if update didnt run } } + if(check) + { + m_rdmmm->log("update"); + } search_for_drives(); if(check)check_and_notify(); return !m_current_drives.empty(); @@ -468,6 +472,7 @@ void RemovableDriveManager::check_and_notify() //std::cout<<"drives count: "<log("drives count not same"); //std::cout<<" vs "<< m_current_drives.size(); if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 49df414827..9eea355f79 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -80,6 +80,7 @@ public: ~RDMMMWrapper(); void register_window(); void list_devices(); + void log(const std::string &msg); protected: void *m_imp; //friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path); diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 7a1108541a..45bd21bcfa 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -61,6 +61,10 @@ void RDMMMWrapper::list_devices() } } } +void RDMMMWrapper::log(const std::string &msg) +{ + NSLog(@"%s", msg.c_str()); +} }}//namespace Slicer::GUI /* From 68125b12a740144461ff408b0533fe412e70287c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 17:42:56 +0100 Subject: [PATCH 092/162] eject button functionality --- src/slic3r/GUI/Plater.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8a96ac4d42..d578649110 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4997,12 +4997,11 @@ void Plater::send_gcode() void Plater::eject_drive() { - if (GUI::RemovableDriveManager::get_instance().update(0, true)) - { - RemovableDriveManager::get_instance().erase_callbacks(); - RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); - RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); - } + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().erase_callbacks(); + RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); + RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); + } void Plater::drive_ejected_callback() { From 19789d78c21a86075d0f7f09473ba5e18603fb99 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Wed, 11 Dec 2019 17:39:34 +0100 Subject: [PATCH 093/162] macos eject --- src/slic3r/GUI/RemovableDriveManager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index afe5ee7393..ab2dd10eb2 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -221,15 +221,17 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP #else void RemovableDriveManager::search_for_drives() { - + + m_current_drives.clear(); + m_current_drives.reserve(26); + #if __APPLE__ if(m_rdmmm) { m_rdmmm->list_devices(); } #else - m_current_drives.clear(); - m_current_drives.reserve(26); + //search /media/* folder search_path("/media/*", "/media"); From 1d25201a12cce36b55ad6268ac491d4fcbda5a33 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 11 Dec 2019 18:30:03 +0100 Subject: [PATCH 094/162] linux eject --- src/slic3r/GUI/GUI_App.cpp | 6 +++--- src/slic3r/GUI/RemovableDriveManager.cpp | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b83ecbedc8..c9ed88f84a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -274,9 +274,9 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); - - //RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); - +#if __linux__ + RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); +#endif // Preset updating & Configwizard are done after the above initializations, // and after MainFrame is created & shown. diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ab2dd10eb2..d5f2244095 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -429,10 +429,6 @@ bool RemovableDriveManager::update(const long time, bool check) return false; // return value shouldnt matter if update didnt run } } - if(check) - { - m_rdmmm->log("update"); - } search_for_drives(); if(check)check_and_notify(); return !m_current_drives.empty(); @@ -474,7 +470,7 @@ void RemovableDriveManager::check_and_notify() //std::cout<<"drives count: "<log("drives count not same"); + //m_rdmmm->log("drives count not same"); //std::cout<<" vs "<< m_current_drives.size(); if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { @@ -505,13 +501,16 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) } bool RemovableDriveManager::is_last_drive_removed() { + std::cout<<"is last: "< Date: Thu, 12 Dec 2019 10:48:33 +0100 Subject: [PATCH 095/162] eject button after export --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/RemovableDriveManager.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index c9ed88f84a..f601cd4bc7 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -274,7 +274,7 @@ bool GUI_App::on_init_inner() this->obj_manipul()->update_if_dirty(); -#if __linux__ +#if !__APPLE__ RemovableDriveManager::get_instance().update(wxGetLocalTime(), true); #endif diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d578649110..eb5f6d4850 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4158,7 +4158,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const if (sidebar->show_reslice(false) | sidebar->show_export(true) | sidebar->show_send(send_gcode_shown) | - sidebar->show_disconnect(disconnect_shown)) + sidebar->show_disconnect(false/*disconnect_shown*/)) sidebar->Layout(); } else @@ -4709,12 +4709,13 @@ void Plater::export_gcode() fs::path path = into_path(dlg.GetPath()); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = std::move(path); - RemovableDriveManager::get_instance().update(0, true); - RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); - } if (! output_path.empty()) + { + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); p->export_gcode(std::move(output_path), PrintHostJob()); + } } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index d5f2244095..7ab34204bc 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -410,7 +410,7 @@ void RemovableDriveManager::init() { //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); #if _WIN32 - register_window(); + //register_window(); #elif __APPLE__ m_rdmmm->register_window(); #endif @@ -501,16 +501,16 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) } bool RemovableDriveManager::is_last_drive_removed() { - std::cout<<"is last: "< Date: Thu, 12 Dec 2019 14:56:30 +0100 Subject: [PATCH 096/162] button show after write --- src/slic3r/GUI/Plater.cpp | 8 ++++-- src/slic3r/GUI/RemovableDriveManager.cpp | 35 +++--------------------- src/slic3r/GUI/RemovableDriveManager.hpp | 4 +-- 3 files changed, 10 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index eb5f6d4850..cefe31e90b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3179,6 +3179,7 @@ void Plater::priv::update_fff_scene() this->preview->reload_print(); // In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: view3D->reload_scene(true); + show_action_buttons(false); } void Plater::priv::update_sla_scene() @@ -4158,7 +4159,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const if (sidebar->show_reslice(false) | sidebar->show_export(true) | sidebar->show_send(send_gcode_shown) | - sidebar->show_disconnect(false/*disconnect_shown*/)) + sidebar->show_disconnect(disconnect_shown)) sidebar->Layout(); } else @@ -4712,9 +4713,10 @@ void Plater::export_gcode() } if (! output_path.empty()) { - RemovableDriveManager::get_instance().update(0, true); - RemovableDriveManager::get_instance().set_last_save_path(output_path.string()); + std::string path = output_path.string(); p->export_gcode(std::move(output_path), PrintHostJob()); + RemovableDriveManager::get_instance().update(0, true); + RemovableDriveManager::get_instance().set_last_save_path(path); } } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7ab34204bc..cd360b580f 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -24,9 +24,6 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, namespace Slic3r { namespace GUI { -//std::vector RemovableDriveManager::m_current_drives; -//std::vector> RemovableDriveManager::m_callbacks; - #if _WIN32 INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -42,7 +39,6 @@ void RemovableDriveManager::search_for_drives() std::string path (1,(char)('A' + i)); path+=":"; UINT drive_type = GetDriveTypeA(path.c_str()); - //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) { path += "\\"; @@ -74,12 +69,9 @@ void RemovableDriveManager::search_for_drives() } } } - //std::cout << "found drives:" << m_current_drives.size() << "\n"; } void RemovableDriveManager::eject_drive(const std::string &path) { - - //if (!update() || !is_drive_mounted(path)) if(m_current_drives.empty()) return; for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) @@ -88,7 +80,6 @@ void RemovableDriveManager::eject_drive(const std::string &path) { std::string mpath = "\\\\.\\" + path; mpath = mpath.substr(0, mpath.size() - 1); - //std::cout << "Ejecting " << mpath << "\n"; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { @@ -138,7 +129,7 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) } void RemovableDriveManager::register_window() { - std::cout << "Registering for device notification\n"; + //creates new unvisible window that is recieving callbacks from system WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; @@ -181,9 +172,6 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP LRESULT lRet = 1; static HDEVNOTIFY hDeviceNotify; - static HWND hEditWnd; - static ULONGLONG msgCount = 0; - switch (message) { case WM_CREATE: @@ -194,11 +182,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; NotificationFilter.dbcc_classguid = WceusbshGUID; - hDeviceNotify = RegisterDeviceNotification( - hWnd, // events recipient - &NotificationFilter, // type of device - DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle - ); + hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); break; case WM_DEVICECHANGE: @@ -280,7 +264,6 @@ void RemovableDriveManager::search_for_drives() } - //std::cout << "found drives:" < RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - //std::cout<<"drives count: "<log("drives count not same"); - //std::cout<<" vs "<< m_current_drives.size(); if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) @@ -481,7 +461,6 @@ void RemovableDriveManager::check_and_notify() } m_drives_count = m_current_drives.size(); } - //std::cout<<"\n"; } void RemovableDriveManager::add_callback(std::function callback) { @@ -522,10 +501,4 @@ void RemovableDriveManager::reset_last_save_path() { m_last_save_path = ""; } - -void RemovableDriveManager::print() -{ - //std::cout << "Removed Device: "<<(int)is_last_drive_removed()<<"\n"; - std::cout << "notified\n"; -} -}}//namespace Slicer::Gui:: +}}//namespace Slicer::Gui diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 9eea355f79..b4fc71e265 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -32,7 +32,7 @@ public: //update() searches for removable devices, returns false if empty. void init(); - bool update(const long time = 0, bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0,const bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); std::string get_last_save_path(); @@ -44,8 +44,6 @@ public: void set_last_save_path(const std::string &path); bool is_last_drive_removed(); bool is_last_drive_removed_with_update(const long time = 0); // param as update() - void print(); - private: RemovableDriveManager(); void search_for_drives(); From 5a9ec0d0743ccc51e0edf476cd784f5cf119692f Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 12 Dec 2019 15:43:14 +0100 Subject: [PATCH 097/162] button show after write --- src/slic3r/GUI/Plater.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cefe31e90b..910de4722f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3179,7 +3179,7 @@ void Plater::priv::update_fff_scene() this->preview->reload_print(); // In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: view3D->reload_scene(true); - show_action_buttons(false); + } void Plater::priv::update_sla_scene() @@ -3578,6 +3578,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) default: break; } + show_action_buttons(false); + if (canceled) { if (wxGetApp().get_mode() == comSimple) sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now"); From 8e1292f353468ad820315a773bdcf18d9cbd7e27 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 13 Dec 2019 11:52:08 +0100 Subject: [PATCH 098/162] comments --- src/slic3r/GUI/RemovableDriveManager.cpp | 24 ++++++++++++++++++---- src/slic3r/GUI/RemovableDriveManager.hpp | 26 ++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index cd360b580f..02681b7daf 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -30,7 +30,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); - m_current_drives.reserve(26); + //get logical drives flags by letter in alphabetical order DWORD drives_mask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { @@ -39,6 +39,7 @@ void RemovableDriveManager::search_for_drives() std::string path (1,(char)('A' + i)); path+=":"; UINT drive_type = GetDriveTypeA(path.c_str()); + // DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives) if (drive_type == DRIVE_REMOVABLE) { // get name of drive @@ -51,10 +52,12 @@ void RemovableDriveManager::search_for_drives() BOOL error = GetVolumeInformationW(wpath.c_str(), &volume_name[0], sizeof(volume_name), NULL, NULL, NULL, &file_system_name[0], sizeof(file_system_name)); if(error != 0) { + /* if (volume_name == L"") { volume_name = L"REMOVABLE DRIVE"; } + */ if (file_system_name != L"") { ULARGE_INTEGER free_space; @@ -78,6 +81,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) { if ((*it).path == path) { + // get handle to device std::string mpath = "\\\\.\\" + path; mpath = mpath.substr(0, mpath.size() - 1); HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); @@ -87,8 +91,12 @@ void RemovableDriveManager::eject_drive(const std::string &path) return; } DWORD deviceControlRetVal(0); + //these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger. + //sd cards does trigger WM_DEVICECHANGE messege, usb drives dont + DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + // some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); if (error == 0) { @@ -130,11 +138,12 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) void RemovableDriveManager::register_window() { //creates new unvisible window that is recieving callbacks from system + // structure to register WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.hInstance = reinterpret_cast(GetModuleHandle(0)); - wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback); + wndClass.lpfnWndProc = reinterpret_cast(WinProcCallback);//this is callback wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); @@ -169,6 +178,9 @@ void RemovableDriveManager::register_window() INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + // here we need to catch messeges about device removal + // problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device. + //uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates LRESULT lRet = 1; static HDEVNOTIFY hDeviceNotify; @@ -187,6 +199,7 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP case WM_DEVICECHANGE: { + // here is the important if(wParam == DBT_DEVICEREMOVECOMPLETE) { - RemovableDriveManager::get_instance().update(0, true); @@ -207,9 +220,9 @@ void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); - m_current_drives.reserve(26); #if __APPLE__ + // if on macos obj-c class will enumerate if(m_rdmmm) { m_rdmmm->list_devices(); @@ -287,6 +300,8 @@ void RemovableDriveManager::search_path(const std::string &path,const std::strin } void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path) { + //confirms if the file is removable drive and adds it to vector + //if not same file system - could be removable drive if(!compare_filesystem_id(path, parent_path)) { @@ -335,7 +350,8 @@ void RemovableDriveManager::eject_drive(const std::string &path) } } std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; - +// there is no usable command in c++ so terminal command is used instead +// but neither triggers "succesful safe removal messege" std::string command = ""; #if __APPLE__ command = "diskutil unmount "; diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index b4fc71e265..ac1645df7b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -29,26 +29,34 @@ public: } RemovableDriveManager(RemovableDriveManager const&) = delete; void operator=(RemovableDriveManager const&) = delete; - - //update() searches for removable devices, returns false if empty. + //call only once. on apple register for unmnount callbacks. on windows register for device notification is prepared but not called (eject usb drive on widnows doesnt trigger the callback, sdc ard does), also enumerates devices for first time so init shoud be called on linux too. void init(); - bool update(const long time = 0,const bool check = false); //time = 0 is forced update, time expects wxGetLocalTime() + //update() searches for removable devices, returns false if empty. /time = 0 is forced update, time expects wxGetLocalTime() + bool update(const long time = 0,const bool check = false); bool is_drive_mounted(const std::string &path); void eject_drive(const std::string &path); + //returns path to last drive which was used, if none was used, returns device that was enumerated last std::string get_last_save_path(); + //returns path to last drive which was used, if none was used, returns empty string std::string get_drive_path(); std::vector get_all_drives(); bool is_path_on_removable_drive(const std::string &path); - void add_callback(std::function callback); // callback will notify only if device with last save path was removed - void erase_callbacks(); // erases all callbacks added by add_callback() + // callback will notify only if device with last save path was removed + void add_callback(std::function callback); + // erases all callbacks added by add_callback() + void erase_callbacks(); + // marks one of the eveices in vector as last used void set_last_save_path(const std::string &path); bool is_last_drive_removed(); - bool is_last_drive_removed_with_update(const long time = 0); // param as update() + // param as update() + bool is_last_drive_removed_with_update(const long time = 0); private: RemovableDriveManager(); void search_for_drives(); + //triggers callbacks if last used drive was removed void check_and_notify(); - std::string get_drive_from_path(const std::string& path);//returns drive path (same as path in DriveData) if exists otherwise empty string "" + //returns drive path (same as path in DriveData) if exists otherwise empty string "" + std::string get_drive_from_path(const std::string& path); void reset_last_save_path(); std::vector m_current_drives; @@ -58,8 +66,8 @@ private: std::string m_last_save_path; #if _WIN32 + //registers for notifications by creating invisible window void register_window(); - //INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #else #if __APPLE__ RDMMMWrapper * m_rdmmm; @@ -69,7 +77,7 @@ private: void inspect_file(const std::string &path, const std::string &parent_path); #endif }; - +// apple wrapper for RemovableDriveManagerMM which searches for drives and/or ejects them #if __APPLE__ class RDMMMWrapper { From acab61fa5430ae3c983e9c08e5ff1e7159319af1 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 13 Dec 2019 13:04:09 +0100 Subject: [PATCH 099/162] comments --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 910de4722f..52255d1763 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3577,7 +3577,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) break; default: break; } - + //added to show disconnect_button after writing show_action_buttons(false); if (canceled) { From f3ecf55d3840634941a0f9b053516d20a183a6a5 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 26 Nov 2019 14:19:29 +0100 Subject: [PATCH 100/162] removable drive manager - Windows part --- src/slic3r/GUI/AppConfig.cpp | 8 ++ src/slic3r/GUI/RemovableDriveManager.cpp | 150 +++++++++++++++++++++++ src/slic3r/GUI/RemovableDriveManager.hpp | 33 +++++ 3 files changed, 191 insertions(+) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 7055822513..f24bde2426 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -21,6 +21,7 @@ #include #include "I18N.hpp" +#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -357,7 +358,14 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { +<<<<<<< HEAD +======= + if (GUI::RemovableDriveManager::getInstance().update()) + { + return GUI::RemovableDriveManager::getInstance().getLastDrivePath(); + } +>>>>>>> removable drive manager - Windows part const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 02681b7daf..ba5ab50727 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,4 +1,5 @@ #include "RemovableDriveManager.hpp" +<<<<<<< HEAD #include #include "boost/nowide/convert.hpp" @@ -66,10 +67,72 @@ void RemovableDriveManager::search_for_drives() { path += "\\"; m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); +======= + +#include +#include +#include +#include + +//#include +//#include "libslic3r/Utils.hpp" + +DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, + 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); + +namespace Slic3r { +namespace GUI { + +std::vector RemovableDriveManager::currentDrives; + +bool RemovableDriveManager::update() +{ + searchForDrives(currentDrives); + return !currentDrives.empty(); +} +void RemovableDriveManager::searchForDrives(std::vector& newDrives) +{ + newDrives.clear(); + newDrives.reserve(26); + DWORD drivesMask = GetLogicalDrives(); + for (size_t i = 0; i < 26; i++) + { + if(drivesMask & (1 << i)) + { + std::string path (1,(char)('A' + i)); + path+=":"; + UINT driveType = GetDriveTypeA(path.c_str()); + //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) + { + newDrives.push_back(DriveData(volumeName, path)); +>>>>>>> removable drive manager - Windows part } } } } +<<<<<<< HEAD } } } @@ -518,3 +581,90 @@ void RemovableDriveManager::reset_last_save_path() m_last_save_path = ""; } }}//namespace Slicer::Gui +======= + else if(driveType == 3)//disks and usb drives + { + } + } + } + +} + +void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) +{ + currentDrives.clear(); + currentDrives.reserve(26); + for (auto it = newDrives.begin(); it != newDrives.end(); ++it) + { + currentDrives.push_back(*it); + } +} +void RemovableDriveManager::printDrivesToLog() +{ + //std::cout<<"current drives:"<< currentDrives.size() <<"\n"; + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + //BOOST_LOG_TRIVIAL(trace) << boost::format("found disk %1%:") % ('A' + i); + //std::cout << /*std::string((*it).name.begin(), (*it).name.end()) << "(" << */(*it).path << ":/, "; + } + //std::cout << "\n"; +} +bool RemovableDriveManager::isDriveMounted(std::string path) +{ + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + return true; + } + } + return false; +} +void RemovableDriveManager::ejectDrive(std::string path) +{ + if (!update() || !isDriveMounted(path)) + return; + + path = "\\\\.\\"+path; + HANDLE handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if(handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << path << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0,nullptr , 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if(error != 0) + std::cout << "Ejected " << path << "\n"; + else + std::cerr << "Ejecting " << path << " failed "<< deviceControlRetVal << " " << GetLastError() <<" \n"; + + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + currentDrives.erase(it); + break; + } + } +} +std::string RemovableDriveManager::getLastDrivePath() +{ + if (!currentDrives.empty()) + { + return currentDrives.back().path; + } + return ""; +} +void RemovableDriveManager::getAllDrives(std::vector& drives) +{ + drives.clear(); + drives.reserve(26); + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + drives.push_back(*it); + } +} +}} +>>>>>>> removable drive manager - Windows part diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index ac1645df7b..a5abde72d0 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -6,6 +6,7 @@ namespace Slic3r { namespace GUI { +<<<<<<< HEAD #if __APPLE__ class RDMMMWrapper; #endif @@ -23,12 +24,25 @@ friend class RDMMMWrapper; #endif public: static RemovableDriveManager& get_instance() +======= +struct DriveData +{ + std::wstring name; + std::string path; + DriveData(std::wstring n, std::string p):name(n),path(p){} +}; +class RemovableDriveManager +{ +public: + static RemovableDriveManager& getInstance() +>>>>>>> removable drive manager - Windows part { static RemovableDriveManager instance; return instance; } RemovableDriveManager(RemovableDriveManager const&) = delete; void operator=(RemovableDriveManager const&) = delete; +<<<<<<< HEAD //call only once. on apple register for unmnount callbacks. on windows register for device notification is prepared but not called (eject usb drive on widnows doesnt trigger the callback, sdc ard does), also enumerates devices for first time so init shoud be called on linux too. void init(); //update() searches for removable devices, returns false if empty. /time = 0 is forced update, time expects wxGetLocalTime() @@ -94,3 +108,22 @@ protected: #endif }} #endif +======= + + //update() searches for removable devices, returns false if empty. + static bool update(); + static bool isDriveMounted(std::string path); + static void ejectDrive(std::string path); + static std::string getLastDrivePath(); + static void getAllDrives(std::vector& drives); +private: + RemovableDriveManager(){} + static void searchForDrives(std::vector& newDrives); + static void printDrivesToLog(); + static void updateCurrentDrives(const std::vector& newDrives); + static std::vector currentDrives; + +}; +}} +#endif +>>>>>>> removable drive manager - Windows part From 4bf8a0ef24ea0a2212d6c8cf2661d2617c4af773 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 26 Nov 2019 15:52:18 +0100 Subject: [PATCH 101/162] removable drives manager linux part --- src/slic3r/GUI/RemovableDriveManager.cpp | 166 +++++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.hpp | 10 +- 2 files changed, 132 insertions(+), 44 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index ba5ab50727..e613320454 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -69,27 +69,35 @@ void RemovableDriveManager::search_for_drives() m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); ======= -#include -#include + + #include #include -//#include -//#include "libslic3r/Utils.hpp" +#if _WIN32 +#include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); +#else +//linux includes +#include +#include +#include +#include +#include +#endif namespace Slic3r { namespace GUI { std::vector RemovableDriveManager::currentDrives; -bool RemovableDriveManager::update() -{ - searchForDrives(currentDrives); - return !currentDrives.empty(); -} + + + +#if _WIN32 void RemovableDriveManager::searchForDrives(std::vector& newDrives) { newDrives.clear(); @@ -589,37 +597,6 @@ void RemovableDriveManager::reset_last_save_path() } } - -void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) -{ - currentDrives.clear(); - currentDrives.reserve(26); - for (auto it = newDrives.begin(); it != newDrives.end(); ++it) - { - currentDrives.push_back(*it); - } -} -void RemovableDriveManager::printDrivesToLog() -{ - //std::cout<<"current drives:"<< currentDrives.size() <<"\n"; - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - //BOOST_LOG_TRIVIAL(trace) << boost::format("found disk %1%:") % ('A' + i); - //std::cout << /*std::string((*it).name.begin(), (*it).name.end()) << "(" << */(*it).path << ":/, "; - } - //std::cout << "\n"; -} -bool RemovableDriveManager::isDriveMounted(std::string path) -{ - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - if ((*it).path == path) - { - return true; - } - } - return false; -} void RemovableDriveManager::ejectDrive(std::string path) { if (!update() || !isDriveMounted(path)) @@ -649,6 +626,115 @@ void RemovableDriveManager::ejectDrive(std::string path) } } } +#else +void RemovableDriveManager::searchForDrives(std::vector& newDrives) +{ + struct stat buf; + std::string path(std::getenv("USER")); + std::string pp(path); + + newDrives.clear(); + newDrives.reserve(26); + + //search /media/* folder + stat("/media/",&buf); + std::cout << "/media ID: " <& newDrives,const std::string path, const dev_t parentDevID) +{ + glob_t globbuf; + globbuf.gl_offs = 2; + std::cout<<"searching "<& newDrives) +{ + currentDrives.clear(); + currentDrives.reserve(26); + for (auto it = newDrives.begin(); it != newDrives.end(); ++it) + { + currentDrives.push_back(*it); + } +} +bool RemovableDriveManager::isDriveMounted(std::string path) +{ + for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + { + if ((*it).path == path) + { + return true; + } + } + return false; +} + std::string RemovableDriveManager::getLastDrivePath() { if (!currentDrives.empty()) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index a5abde72d0..157f670b31 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -27,9 +27,9 @@ public: ======= struct DriveData { - std::wstring name; + std::string name; std::string path; - DriveData(std::wstring n, std::string p):name(n),path(p){} + DriveData(std::string n, std::string p):name(n),path(p){} }; class RemovableDriveManager { @@ -119,10 +119,12 @@ protected: private: RemovableDriveManager(){} static void searchForDrives(std::vector& newDrives); - static void printDrivesToLog(); static void updateCurrentDrives(const std::vector& newDrives); static std::vector currentDrives; - +#if _WIN32 +#else + static void searchPath(std::vector& newDrives,const std::string path, const dev_t parentDevID); +#endif }; }} #endif From 72f1adbb443a37cd2ffc9f005e63549f032085c0 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 11:33:36 +0100 Subject: [PATCH 102/162] refactoring --- src/slic3r/GUI/AppConfig.cpp | 2 +- src/slic3r/GUI/RemovableDriveManager.cpp | 118 +++++++++++------------ src/slic3r/GUI/RemovableDriveManager.hpp | 15 ++- 3 files changed, 64 insertions(+), 71 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index f24bde2426..9f294a3b60 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -363,7 +363,7 @@ std::string AppConfig::get_last_output_dir(const std::string &alt) const ======= if (GUI::RemovableDriveManager::getInstance().update()) { - return GUI::RemovableDriveManager::getInstance().getLastDrivePath(); + return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); } >>>>>>> removable drive manager - Windows part const auto it = m_storage.find(""); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index e613320454..30f6c9b290 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,5 +1,6 @@ #include "RemovableDriveManager.hpp" <<<<<<< HEAD +<<<<<<< HEAD #include #include "boost/nowide/convert.hpp" @@ -71,13 +72,16 @@ void RemovableDriveManager::search_for_drives() +======= +>>>>>>> refactoring #include #include - +#include "boost/nowide/convert.hpp" #if _WIN32 #include #include +#include DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); #else @@ -92,16 +96,13 @@ DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, namespace Slic3r { namespace GUI { -std::vector RemovableDriveManager::currentDrives; - - - +std::vector RemovableDriveManager::m_current_drives; #if _WIN32 -void RemovableDriveManager::searchForDrives(std::vector& newDrives) +void RemovableDriveManager::search_for_drives() { - newDrives.clear(); - newDrives.reserve(26); + m_current_drives.clear(); + m_current_drives.reserve(26); DWORD drivesMask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { @@ -134,8 +135,12 @@ void RemovableDriveManager::searchForDrives(std::vector& newDrives) //std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n"; if (freeSpace.QuadPart > 0) { +<<<<<<< HEAD newDrives.push_back(DriveData(volumeName, path)); >>>>>>> removable drive manager - Windows part +======= + m_current_drives.push_back(DriveData(boost::nowide::narrow(volumeName), path)); +>>>>>>> refactoring } } } @@ -597,49 +602,51 @@ void RemovableDriveManager::reset_last_save_path() } } -void RemovableDriveManager::ejectDrive(std::string path) +void RemovableDriveManager::eject_drive(const std::string &path) { - if (!update() || !isDriveMounted(path)) - return; - path = "\\\\.\\"+path; - HANDLE handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - if(handle == INVALID_HANDLE_VALUE) - { - std::cerr << "Ejecting " << path << " failed " << GetLastError() << " \n"; + //if (!update() || !is_drive_mounted(path)) + if(m_current_drives.empty()) return; - } - DWORD deviceControlRetVal(0); - BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0,nullptr , 0, &deviceControlRetVal, nullptr); - CloseHandle(handle); - if(error != 0) - std::cout << "Ejected " << path << "\n"; - else - std::cerr << "Ejecting " << path << " failed "<< deviceControlRetVal << " " << GetLastError() <<" \n"; - - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { - currentDrives.erase(it); + std::string mpath = "\\\\.\\" + path; + HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if (handle == INVALID_HANDLE_VALUE) + { + std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n"; + return; + } + DWORD deviceControlRetVal(0); + BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); + CloseHandle(handle); + if (error != 0) + std::cout << "Ejected " << mpath << "\n"; + else + std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; + + + m_current_drives.erase(it); break; } } } #else -void RemovableDriveManager::searchForDrives(std::vector& newDrives) +void RemovableDriveManager::search_for_drives() { struct stat buf; std::string path(std::getenv("USER")); std::string pp(path); - newDrives.clear(); - newDrives.reserve(26); + m_current_drives.clear(); + m_current_Drives.reserve(26); //search /media/* folder stat("/media/",&buf); std::cout << "/media ID: " <& newDrives) stat(pp.c_str() ,&buf); std::cout << pp <<" ID: " <& newDrives,const std::string path, const dev_t parentDevID) +void RemovableDriveManager::search_path(const std::string &path,const dev_t &parentDevID) { glob_t globbuf; globbuf.gl_offs = 2; @@ -679,17 +686,17 @@ void RemovableDriveManager::searchPath(std::vector& newDrives,const s std::cout << buf.st_dev << "\n"; if(buf.st_dev != parentDevID)// not same file system { - newDrives.push_back(DriveData(name,globbuf.gl_pathv[i])); + m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); } } globfree(&globbuf); } -void RemovableDriveManager::ejectDrive(std::string path) +void RemovableDriveManager::eject_drive(const std::string &path) { - if (currentDrives.empty()) + if (m_current_drives.empty()) return; - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if((*it).path == path) { @@ -700,7 +707,7 @@ void RemovableDriveManager::ejectDrive(std::string path) int errsv = errno; std::cerr<<"Ejecting failed Error "<< errsv<<"\n"; } - currentDrives.erase(it); + m_current_drives.erase(it); break; } @@ -710,22 +717,14 @@ void RemovableDriveManager::ejectDrive(std::string path) #endif bool RemovableDriveManager::update() { - searchForDrives(currentDrives); - return !currentDrives.empty(); + search_for_drives(); + return !m_current_drives.empty(); } -void RemovableDriveManager::updateCurrentDrives(const std::vector& newDrives) + +bool RemovableDriveManager::is_drive_mounted(const std::string &path) { - currentDrives.clear(); - currentDrives.reserve(26); - for (auto it = newDrives.begin(); it != newDrives.end(); ++it) - { - currentDrives.push_back(*it); - } -} -bool RemovableDriveManager::isDriveMounted(std::string path) -{ - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { @@ -735,22 +734,17 @@ bool RemovableDriveManager::isDriveMounted(std::string path) return false; } -std::string RemovableDriveManager::getLastDrivePath() +std::string RemovableDriveManager::get_last_drive_path() { - if (!currentDrives.empty()) + if (!m_current_drives.empty()) { - return currentDrives.back().path; + return m_current_drives.back().path; } return ""; } -void RemovableDriveManager::getAllDrives(std::vector& drives) +std::vector RemovableDriveManager::get_all_drives() { - drives.clear(); - drives.reserve(26); - for (auto it = currentDrives.begin(); it != currentDrives.end(); ++it) - { - drives.push_back(*it); - } + return m_current_drives; } }} >>>>>>> removable drive manager - Windows part diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 157f670b31..c001644460 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -112,18 +112,17 @@ protected: //update() searches for removable devices, returns false if empty. static bool update(); - static bool isDriveMounted(std::string path); - static void ejectDrive(std::string path); - static std::string getLastDrivePath(); - static void getAllDrives(std::vector& drives); + static bool is_drive_mounted(const std::string &path); + static void eject_drive(const std::string &path); + static std::string get_last_drive_path(); + static std::vector get_all_drives(); private: RemovableDriveManager(){} - static void searchForDrives(std::vector& newDrives); - static void updateCurrentDrives(const std::vector& newDrives); - static std::vector currentDrives; + static void search_for_drives(); + static std::vector m_current_drives; #if _WIN32 #else - static void searchPath(std::vector& newDrives,const std::string path, const dev_t parentDevID); + static void search_path(const std::string &path, const dev_t &parentDevID); #endif }; }} From 1ec7fc23e24b7d981b513d52a039201f2cac506f Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 13:30:45 +0100 Subject: [PATCH 103/162] check if last path is on rem drive --- src/slic3r/GUI/AppConfig.cpp | 5 +- src/slic3r/GUI/Plater.cpp | 8 + src/slic3r/GUI/RemovableDriveManager.cpp | 230 ----------------------- src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 4 files changed, 13 insertions(+), 231 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 9f294a3b60..e27fa1be65 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -21,7 +21,6 @@ #include #include "I18N.hpp" -#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -359,6 +358,7 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { <<<<<<< HEAD +<<<<<<< HEAD ======= if (GUI::RemovableDriveManager::getInstance().update()) @@ -366,6 +366,9 @@ std::string AppConfig::get_last_output_dir(const std::string &alt) const return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); } >>>>>>> removable drive manager - Windows part +======= + +>>>>>>> check if last path is on rem drive const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 52255d1763..aff162401f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4693,11 +4693,19 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); +<<<<<<< HEAD if (GUI::RemovableDriveManager::get_instance().update()) { if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) { start_dir = RemovableDriveManager::get_instance().get_drive_path(); +======= + if (GUI::RemovableDriveManager::getInstance().update()) + { + if (!RemovableDriveManager::getInstance().is_path_on_removable_drive(start_dir)) + { + start_dir = RemovableDriveManager::getInstance().get_last_drive_path(); +>>>>>>> check if last path is on rem drive } } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 30f6c9b290..02681b7daf 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -1,6 +1,4 @@ #include "RemovableDriveManager.hpp" -<<<<<<< HEAD -<<<<<<< HEAD #include #include "boost/nowide/convert.hpp" @@ -68,84 +66,10 @@ void RemovableDriveManager::search_for_drives() { path += "\\"; m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); -======= - - - -======= ->>>>>>> refactoring -#include -#include -#include "boost/nowide/convert.hpp" - -#if _WIN32 -#include -#include -#include -DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, - 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); -#else -//linux includes -#include -#include -#include -#include -#include -#endif - -namespace Slic3r { -namespace GUI { - -std::vector RemovableDriveManager::m_current_drives; - -#if _WIN32 -void RemovableDriveManager::search_for_drives() -{ - m_current_drives.clear(); - m_current_drives.reserve(26); - DWORD drivesMask = GetLogicalDrives(); - for (size_t i = 0; i < 26; i++) - { - if(drivesMask & (1 << i)) - { - std::string path (1,(char)('A' + i)); - path+=":"; - UINT driveType = GetDriveTypeA(path.c_str()); - //std::cout << "found drive" << (char)('A' + i) << ": type:" < 0) - { -<<<<<<< HEAD - newDrives.push_back(DriveData(volumeName, path)); ->>>>>>> removable drive manager - Windows part -======= - m_current_drives.push_back(DriveData(boost::nowide::narrow(volumeName), path)); ->>>>>>> refactoring } } } } -<<<<<<< HEAD } } } @@ -594,157 +518,3 @@ void RemovableDriveManager::reset_last_save_path() m_last_save_path = ""; } }}//namespace Slicer::Gui -======= - else if(driveType == 3)//disks and usb drives - { - } - } - } - -} -void RemovableDriveManager::eject_drive(const std::string &path) -{ - - //if (!update() || !is_drive_mounted(path)) - if(m_current_drives.empty()) - return; - for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) - { - if ((*it).path == path) - { - std::string mpath = "\\\\.\\" + path; - HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - if (handle == INVALID_HANDLE_VALUE) - { - std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n"; - return; - } - DWORD deviceControlRetVal(0); - BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); - CloseHandle(handle); - if (error != 0) - std::cout << "Ejected " << mpath << "\n"; - else - std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; - - - m_current_drives.erase(it); - break; - } - } -} -#else -void RemovableDriveManager::search_for_drives() -{ - struct stat buf; - std::string path(std::getenv("USER")); - std::string pp(path); - - m_current_drives.clear(); - m_current_Drives.reserve(26); - - //search /media/* folder - stat("/media/",&buf); - std::cout << "/media ID: " < RemovableDriveManager::get_all_drives() -{ - return m_current_drives; -} -}} ->>>>>>> removable drive manager - Windows part diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index c001644460..1e5d240f09 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -116,6 +116,7 @@ protected: static void eject_drive(const std::string &path); static std::string get_last_drive_path(); static std::vector get_all_drives(); + static bool is_path_on_removable_drive(const std::string &path); private: RemovableDriveManager(){} static void search_for_drives(); From 9c79c7f644d0e2155cb7bd1c50bcc4b7b6e03d47 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 27 Nov 2019 14:30:10 +0100 Subject: [PATCH 104/162] prev commit linux part --- src/slic3r/GUI/AppConfig.cpp | 12 -------- src/slic3r/GUI/Plater.cpp | 8 ----- src/slic3r/GUI/RemovableDriveManager.cpp | 3 +- src/slic3r/GUI/RemovableDriveManager.hpp | 37 +----------------------- 4 files changed, 3 insertions(+), 57 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index e27fa1be65..d33d945efb 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -357,18 +357,6 @@ void AppConfig::update_skein_dir(const std::string &dir) std::string AppConfig::get_last_output_dir(const std::string &alt) const { -<<<<<<< HEAD -<<<<<<< HEAD - -======= - if (GUI::RemovableDriveManager::getInstance().update()) - { - return GUI::RemovableDriveManager::getInstance().get_last_drive_path(); - } ->>>>>>> removable drive manager - Windows part -======= - ->>>>>>> check if last path is on rem drive const auto it = m_storage.find(""); if (it != m_storage.end()) { const auto it2 = it->second.find("last_output_path"); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index aff162401f..52255d1763 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4693,19 +4693,11 @@ void Plater::export_gcode() } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); -<<<<<<< HEAD if (GUI::RemovableDriveManager::get_instance().update()) { if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir)) { start_dir = RemovableDriveManager::get_instance().get_drive_path(); -======= - if (GUI::RemovableDriveManager::getInstance().update()) - { - if (!RemovableDriveManager::getInstance().is_path_on_removable_drive(start_dir)) - { - start_dir = RemovableDriveManager::getInstance().get_last_drive_path(); ->>>>>>> check if last path is on rem drive } } wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 02681b7daf..77a387aaf5 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -276,7 +276,6 @@ void RemovableDriveManager::search_for_drives() search_path(path, pp); } - #endif } void RemovableDriveManager::search_path(const std::string &path,const std::string &parent_path) @@ -330,6 +329,7 @@ bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, con dev_t id_b = buf.st_dev; return id_a == id_b; } + void RemovableDriveManager::eject_drive(const std::string &path) { if (m_current_drives.empty()) @@ -518,3 +518,4 @@ void RemovableDriveManager::reset_last_save_path() m_last_save_path = ""; } }}//namespace Slicer::Gui + diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 1e5d240f09..fa42f5e735 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -6,7 +6,6 @@ namespace Slic3r { namespace GUI { -<<<<<<< HEAD #if __APPLE__ class RDMMMWrapper; #endif @@ -24,25 +23,12 @@ friend class RDMMMWrapper; #endif public: static RemovableDriveManager& get_instance() -======= -struct DriveData -{ - std::string name; - std::string path; - DriveData(std::string n, std::string p):name(n),path(p){} -}; -class RemovableDriveManager -{ -public: - static RemovableDriveManager& getInstance() ->>>>>>> removable drive manager - Windows part { static RemovableDriveManager instance; return instance; } RemovableDriveManager(RemovableDriveManager const&) = delete; void operator=(RemovableDriveManager const&) = delete; -<<<<<<< HEAD //call only once. on apple register for unmnount callbacks. on windows register for device notification is prepared but not called (eject usb drive on widnows doesnt trigger the callback, sdc ard does), also enumerates devices for first time so init shoud be called on linux too. void init(); //update() searches for removable devices, returns false if empty. /time = 0 is forced update, time expects wxGetLocalTime() @@ -107,25 +93,4 @@ protected: }; #endif }} -#endif -======= - - //update() searches for removable devices, returns false if empty. - static bool update(); - static bool is_drive_mounted(const std::string &path); - static void eject_drive(const std::string &path); - static std::string get_last_drive_path(); - static std::vector get_all_drives(); - static bool is_path_on_removable_drive(const std::string &path); -private: - RemovableDriveManager(){} - static void search_for_drives(); - static std::vector m_current_drives; -#if _WIN32 -#else - static void search_path(const std::string &path, const dev_t &parentDevID); -#endif -}; -}} -#endif ->>>>>>> removable drive manager - Windows part +#endif \ No newline at end of file From 6de41c6147ec921f0b06e1769d70e94898b31a2a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 12 Dec 2019 15:43:14 +0100 Subject: [PATCH 105/162] button show after write --- src/slic3r/GUI/Plater.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 52255d1763..02f8ace078 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3580,6 +3580,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) //added to show disconnect_button after writing show_action_buttons(false); + show_action_buttons(false); + if (canceled) { if (wxGetApp().get_mode() == comSimple) sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now"); From 2df903640bc4c5e9906aef0bf7a6b9beb3acc169 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 13 Dec 2019 13:23:55 +0100 Subject: [PATCH 106/162] Implemented rescaling for "Remove device" button --- src/slic3r/GUI/Plater.cpp | 58 ++++++++++++++++++--------------- src/slic3r/GUI/wxExtensions.cpp | 8 +++-- src/slic3r/GUI/wxExtensions.hpp | 7 ++++ 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 02f8ace078..cff3164e8e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -699,8 +699,8 @@ struct Sidebar::priv wxButton *btn_export_gcode; wxButton *btn_reslice; - wxButton *btn_send_gcode; - ScalableButton *btn_disconnect; + ScalableButton *btn_send_gcode; + ScalableButton *btn_remove_device; priv(Plater *plater) : plater(plater) {} ~priv(); @@ -849,25 +849,30 @@ Sidebar::Sidebar(Plater *parent) // Buttons underneath the scrolled area - auto init_btn = [this](wxButton **btn, wxString label, const std::string icon_name = "", wxString tooltip = wxEmptyString) { - *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, - wxDefaultSize, wxBU_EXACTFIT); - (*btn)->SetFont(wxGetApp().bold_font()); - (*btn)->SetToolTip(tooltip); + // rescalable bitmap buttons "Send to printer" and "Remove device" - if (!icon_name.empty()) - (*btn)->SetBitmap(create_scaled_bitmap(this, icon_name)); + auto init_scalable_btn = [this](ScalableButton** btn, const std::string& icon_name, wxString tooltip = wxEmptyString) + { + ScalableBitmap bmp = ScalableBitmap(this, icon_name, int(2.5 * wxGetApp().em_unit())); + *btn = new ScalableButton(this, wxID_ANY, bmp, "", wxBU_EXACTFIT); + (*btn)->SetToolTip(tooltip); + (*btn)->Hide(); }; - init_btn(&p->btn_send_gcode, /*_(L("Send to printer"))*/"", "export_gcode", _(L("Send to printer"))); - p->btn_send_gcode->Hide(); - init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots); - init_btn(&p->btn_reslice, _(L("Slice now"))); + init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer"))); + init_scalable_btn(&p->btn_remove_device, "revert_all_" , _(L("Remove device"))); - p->btn_disconnect = new ScalableButton(this, wxID_ANY, "revert_all_", "", - wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT); - p->btn_disconnect->Hide(); - p->btn_disconnect->SetToolTip(_(L("Remove device"))); + // regular buttons "Slice now" and "Export G-code" + + const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4; + auto init_btn = [this](wxButton **btn, wxString label, const int button_height) { + *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, + wxSize(-1, button_height), wxBU_EXACTFIT); + (*btn)->SetFont(wxGetApp().bold_font()); + }; + + init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots , scaled_height); + init_btn(&p->btn_reslice , _(L("Slice now")) , scaled_height); enable_buttons(false); @@ -876,12 +881,10 @@ Sidebar::Sidebar(Plater *parent) auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); complect_btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND); - complect_btns_sizer->Add(p->btn_disconnect); + complect_btns_sizer->Add(p->btn_remove_device); btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5); -// btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5); -// btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(p->scrolled, 1, wxEXPAND); @@ -900,10 +903,7 @@ Sidebar::Sidebar(Plater *parent) p->plater->select_view_3D("Preview"); }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); - p->btn_disconnect->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { - // #dk_FIXME - p->plater->eject_drive(); - }); + p->btn_remove_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); }); } Sidebar::~Sidebar() {} @@ -1049,6 +1049,12 @@ void Sidebar::msw_rescale() p->object_info->msw_rescale(); + p->btn_send_gcode->msw_rescale(); + p->btn_remove_device->msw_rescale(); + const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4; + p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height)); + p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height)); + p->scrolled->Layout(); } @@ -1277,13 +1283,13 @@ void Sidebar::enable_buttons(bool enable) p->btn_reslice->Enable(enable); p->btn_export_gcode->Enable(enable); p->btn_send_gcode->Enable(enable); - p->btn_disconnect->Enable(enable); + p->btn_remove_device->Enable(enable); } bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); } bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); } bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); } -bool Sidebar::show_disconnect(bool show)const { return p->btn_disconnect->Show(show); } +bool Sidebar::show_disconnect(bool show)const { return p->btn_remove_device->Show(show); } bool Sidebar::is_multifilament() { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 302a5e5210..e64a3fce59 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -3935,8 +3935,10 @@ ScalableButton::ScalableButton( wxWindow * parent, const ScalableBitmap& bitmap, const wxString& label /*= wxEmptyString*/, long style /*= wxBU_EXACTFIT | wxNO_BORDER*/) : + m_parent(parent), m_current_icon_name(bitmap.name()), - m_parent(parent) + m_px_cnt(bitmap.px_cnt()), + m_is_horizontal(bitmap.is_horizontal()) { Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style); #ifdef __WXMSW__ @@ -3961,9 +3963,9 @@ void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp) void ScalableButton::msw_rescale() { - SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name)); + SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt, m_is_horizontal)); if (!m_disabled_icon_name.empty()) - SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name)); + SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name, m_px_cnt, m_is_horizontal)); if (m_width > 0 || m_height>0) { diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 7841b62fee..951f7ea8f4 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -729,6 +729,9 @@ public: wxBitmap& bmp() { return m_bmp; } const std::string& name() const{ return m_icon_name; } + int px_cnt()const {return m_px_cnt;} + bool is_horizontal()const {return m_is_horizontal;} + private: wxWindow* m_parent{ nullptr }; wxBitmap m_bmp = wxBitmap(); @@ -1116,6 +1119,10 @@ private: std::string m_disabled_icon_name = ""; int m_width {-1}; // should be multiplied to em_unit int m_height{-1}; // should be multiplied to em_unit + + // bitmap dimensions + int m_px_cnt{ 16 }; + bool m_is_horizontal{ false }; }; From 7d0d70534b70f12de81159fad7d04d93aef5cb26 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 13 Dec 2019 17:56:04 +0100 Subject: [PATCH 107/162] Fixed "actions" buttons size under OSX --- src/slic3r/GUI/Plater.cpp | 13 +++++++++---- src/slic3r/GUI/wxExtensions.cpp | 6 ++++++ src/slic3r/GUI/wxExtensions.hpp | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 72d01b41d8..fa18bd5ea0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -853,18 +853,23 @@ Sidebar::Sidebar(Plater *parent) auto init_scalable_btn = [this](ScalableButton** btn, const std::string& icon_name, wxString tooltip = wxEmptyString) { - ScalableBitmap bmp = ScalableBitmap(this, icon_name, int(2.5 * wxGetApp().em_unit())); +#ifdef __APPLE__ + int bmp_px_cnt = 16; +#else + int bmp_px_cnt = 32; +#endif //__APPLE__ + ScalableBitmap bmp = ScalableBitmap(this, icon_name, bmp_px_cnt); *btn = new ScalableButton(this, wxID_ANY, bmp, "", wxBU_EXACTFIT); (*btn)->SetToolTip(tooltip); (*btn)->Hide(); }; init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer"))); - init_scalable_btn(&p->btn_remove_device, "revert_all_" , _(L("Remove device"))); + init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device"))); // regular buttons "Slice now" and "Export G-code" - const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4; + const int scaled_height = p->btn_remove_device->GetBitmapHeight() + 4; auto init_btn = [this](wxButton **btn, wxString label, const int button_height) { *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, wxSize(-1, button_height), wxBU_EXACTFIT); @@ -880,7 +885,7 @@ Sidebar::Sidebar(Plater *parent) auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); - complect_btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND); + complect_btns_sizer->Add(p->btn_send_gcode); complect_btns_sizer->Add(p->btn_remove_device); btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index e64a3fce59..c359f76624 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -3961,6 +3961,12 @@ void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp) m_disabled_icon_name = bmp.name(); } +int ScalableButton::GetBitmapHeight() +{ + const float scale_factor = get_svg_scale_factor(m_parent); + return int((float)GetBitmap().GetHeight() / scale_factor); +} + void ScalableButton::msw_rescale() { SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt, m_is_horizontal)); diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 951f7ea8f4..26e334def4 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -1110,6 +1110,7 @@ public: void SetBitmap_(const ScalableBitmap& bmp); void SetBitmapDisabled_(const ScalableBitmap &bmp); + int GetBitmapHeight(); void msw_rescale(); From 5a26be1150314f2abd04229e3d69991436a679da Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 13 Dec 2019 18:02:25 +0100 Subject: [PATCH 108/162] message box about succesful removal --- src/slic3r/GUI/Plater.cpp | 11 ++++++-- src/slic3r/GUI/RemovableDriveManager.cpp | 34 ++++++++++++++++++++++-- src/slic3r/GUI/RemovableDriveManager.hpp | 6 +++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 72d01b41d8..f1bdbb23ef 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3583,8 +3583,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) break; default: break; } - //added to show disconnect_button after writing - show_action_buttons(false); + if (canceled) { if (wxGetApp().get_mode() == comSimple) @@ -3593,6 +3592,11 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) } else if (wxGetApp().get_mode() == comSimple) show_action_buttons(false); + else if(RemovableDriveManager::get_instance().get_is_writing()) + { + RemovableDriveManager::get_instance().set_is_writing(false); + show_action_buttons(false); + } } void Plater::priv::on_layer_editing_toggled(bool enable) @@ -4722,6 +4726,7 @@ void Plater::export_gcode() if (! output_path.empty()) { std::string path = output_path.string(); + RemovableDriveManager::get_instance().set_is_writing(true); p->export_gcode(std::move(output_path), PrintHostJob()); RemovableDriveManager::get_instance().update(0, true); RemovableDriveManager::get_instance().set_last_save_path(path); @@ -5016,6 +5021,8 @@ void Plater::eject_drive() } void Plater::drive_ejected_callback() { + wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer."; + wxMessageBox(message); p->show_action_buttons(false); } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 1c2a29b0ba..535d62f83f 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -43,7 +43,7 @@ void RemovableDriveManager::search_for_drives() if (drive_type == DRIVE_REMOVABLE) { // get name of drive - std::wstring wpath = std::wstring(path.begin(), path.end()); + std::wstring wpath = boost::nowide::widen(path);//std::wstring(path.begin(), path.end()); std::wstring volume_name; volume_name.resize(1024); std::wstring file_system_name; @@ -52,6 +52,7 @@ void RemovableDriveManager::search_for_drives() BOOL error = GetVolumeInformationW(wpath.c_str(), &volume_name[0], sizeof(volume_name), NULL, NULL, NULL, &file_system_name[0], sizeof(file_system_name)); if(error != 0) { + volume_name.erase(std::find(volume_name.begin(), volume_name.end(), '\0'), volume_name.end()); /* if (volume_name == L"") { @@ -398,7 +399,9 @@ std::string RemovableDriveManager::get_drive_from_path(const std::string& path) RemovableDriveManager::RemovableDriveManager(): m_drives_count(0), m_last_update(0), - m_last_save_path("") + m_last_save_path(""), + m_last_save_name(""), + m_is_writing(false) #if __APPLE__ , m_rdmmm(new RDMMMWrapper()) #endif @@ -459,6 +462,10 @@ std::string RemovableDriveManager::get_last_save_path() { return m_last_save_path; } +std::string RemovableDriveManager::get_last_save_name() +{ + return m_last_save_name; +} std::vector RemovableDriveManager::get_all_drives() { return m_current_drives; @@ -491,8 +498,22 @@ void RemovableDriveManager::set_last_save_path(const std::string& path) if(last_drive != "") { m_last_save_path = last_drive; + m_last_save_name = get_drive_name(last_drive); } } +std::string RemovableDriveManager::get_drive_name(const std::string& path) +{ + if (m_current_drives.size() == 0) + return ""; + for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) + { + if ((*it).path == path) + { + return (*it).name; + } + } + return ""; +} bool RemovableDriveManager::is_last_drive_removed() { //std::cout<<"is last: "< get_all_drives(); @@ -50,6 +51,9 @@ public: bool is_last_drive_removed(); // param as update() bool is_last_drive_removed_with_update(const long time = 0); + void set_is_writing(const bool b); + bool get_is_writing(); + std::string get_drive_name(const std::string& path); private: RemovableDriveManager(); void search_for_drives(); @@ -64,6 +68,8 @@ private: size_t m_drives_count; long m_last_update; std::string m_last_save_path; + std::string m_last_save_name; + bool m_is_writing;//on device #if _WIN32 //registers for notifications by creating invisible window From 0db9815467d45812f6d727d60ba637613050d964 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 16 Dec 2019 13:53:12 +0100 Subject: [PATCH 109/162] correct beahvior when disconnecting device other way than button in slicer --- src/slic3r/GUI/Plater.cpp | 21 +++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.cpp | 23 +++++++++++++++++++---- src/slic3r/GUI/RemovableDriveManager.hpp | 3 +++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ce29120abc..63521815df 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3600,6 +3600,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) else if(RemovableDriveManager::get_instance().get_is_writing()) { RemovableDriveManager::get_instance().set_is_writing(false); + //RemovableDriveManager::get_instance().erase_callbacks(); + //RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, q)); show_action_buttons(false); } } @@ -4168,8 +4170,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const const auto prin_host_opt = config->option("print_host"); const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); - const bool disconnect_shown = !(RemovableDriveManager::get_instance().is_last_drive_removed()); // #dk_FIXME - + bool disconnect_shown = !RemovableDriveManager::get_instance().is_last_drive_removed() ; // #dk_FIXME // when a background processing is ON, export_btn and/or send_btn are showing if (wxGetApp().app_config->get("background_processing") == "1") { @@ -4735,6 +4736,11 @@ void Plater::export_gcode() p->export_gcode(std::move(output_path), PrintHostJob()); RemovableDriveManager::get_instance().update(0, true); RemovableDriveManager::get_instance().set_last_save_path(path); + if(!RemovableDriveManager::get_instance().is_last_drive_removed()) + { + RemovableDriveManager::get_instance().erase_callbacks(); + RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); + } } } @@ -5019,15 +5025,18 @@ void Plater::send_gcode() void Plater::eject_drive() { RemovableDriveManager::get_instance().update(0, true); - RemovableDriveManager::get_instance().erase_callbacks(); - RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); + //RemovableDriveManager::get_instance().erase_callbacks(); + //RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path()); } void Plater::drive_ejected_callback() { - wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer."; - wxMessageBox(message); + if (RemovableDriveManager::get_instance().get_did_eject()) + { + wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer."; + wxMessageBox(message); + } p->show_action_buttons(false); } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 535d62f83f..5af4362f27 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -106,7 +106,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) return; } CloseHandle(handle); - + m_did_eject = true; m_current_drives.erase(it); break; } @@ -365,6 +365,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) std::cerr<<"Ejecting failed\n"; return; } + m_did_eject = true; m_current_drives.erase(it); break; @@ -401,12 +402,18 @@ RemovableDriveManager::RemovableDriveManager(): m_last_update(0), m_last_save_path(""), m_last_save_name(""), - m_is_writing(false) + m_is_writing(false), + m_did_eject(false) #if __APPLE__ , m_rdmmm(new RDMMMWrapper()) #endif {} - +RemovableDriveManager::~RemovableDriveManager() +{ +#if __APPLE__ + delete m_rdmmm; +#endif +} void RemovableDriveManager::init() { //add_callback([](void) { RemovableDriveManager::get_instance().print(); }); @@ -517,7 +524,7 @@ std::string RemovableDriveManager::get_drive_name(const std::string& path) bool RemovableDriveManager::is_last_drive_removed() { //std::cout<<"is last: "< Date: Mon, 16 Dec 2019 14:06:25 +0100 Subject: [PATCH 110/162] macos first update bug fix --- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 5af4362f27..f8d7883f55 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -422,7 +422,7 @@ void RemovableDriveManager::init() #elif __APPLE__ m_rdmmm->register_window(); #endif - update(); + update(0, true); } bool RemovableDriveManager::update(const long time,const bool check) { From b61afdfd085808f4c3a9b072edc98cdf2084f7a1 Mon Sep 17 00:00:00 2001 From: Slic3rPE Date: Mon, 16 Dec 2019 15:46:25 +0100 Subject: [PATCH 111/162] macos detecting also mounting of dev --- src/slic3r/GUI/RemovableDriveManagerMM.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 45bd21bcfa..3bb017a3aa 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -23,6 +23,7 @@ { NSLog(@"add unmount observer"); [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil]; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidMountNotification object:nil]; } -(NSArray*) list_dev { From bfc9dda1f6bc9efa9e2616c98ba38c3b52f2ad3f Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 16 Dec 2019 15:47:36 +0100 Subject: [PATCH 112/162] save last path earlier --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 63521815df..7cd4f195ba 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4733,9 +4733,9 @@ void Plater::export_gcode() { std::string path = output_path.string(); RemovableDriveManager::get_instance().set_is_writing(true); - p->export_gcode(std::move(output_path), PrintHostJob()); RemovableDriveManager::get_instance().update(0, true); RemovableDriveManager::get_instance().set_last_save_path(path); + p->export_gcode(std::move(output_path), PrintHostJob()); if(!RemovableDriveManager::get_instance().is_last_drive_removed()) { RemovableDriveManager::get_instance().erase_callbacks(); From a029e689d81fd099d0a129bf0cdacda2b4b67762 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 16 Dec 2019 17:15:27 +0100 Subject: [PATCH 113/162] verification of save path --- src/slic3r/GUI/Plater.cpp | 18 +++++++++++++----- src/slic3r/GUI/RemovableDriveManager.cpp | 20 ++++++++++++++------ src/slic3r/GUI/RemovableDriveManager.hpp | 3 ++- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7cd4f195ba..29b83bebab 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3597,12 +3597,18 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) } else if (wxGetApp().get_mode() == comSimple) show_action_buttons(false); - else if(RemovableDriveManager::get_instance().get_is_writing()) + if(RemovableDriveManager::get_instance().get_is_writing()) { RemovableDriveManager::get_instance().set_is_writing(false); - //RemovableDriveManager::get_instance().erase_callbacks(); - //RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, q)); - show_action_buttons(false); + RemovableDriveManager::get_instance().verify_last_save_path(); + if (!RemovableDriveManager::get_instance().is_last_drive_removed()) + { + + RemovableDriveManager::get_instance().erase_callbacks(); + RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, q)); + show_action_buttons(false); + } + } } @@ -4734,13 +4740,15 @@ void Plater::export_gcode() std::string path = output_path.string(); RemovableDriveManager::get_instance().set_is_writing(true); RemovableDriveManager::get_instance().update(0, true); - RemovableDriveManager::get_instance().set_last_save_path(path); p->export_gcode(std::move(output_path), PrintHostJob()); + RemovableDriveManager::get_instance().set_last_save_path(path); + /* if(!RemovableDriveManager::get_instance().is_last_drive_removed()) { RemovableDriveManager::get_instance().erase_callbacks(); RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); } + */ } } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index f8d7883f55..52a8c2b77e 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -402,6 +402,7 @@ RemovableDriveManager::RemovableDriveManager(): m_last_update(0), m_last_save_path(""), m_last_save_name(""), + m_last_save_path_verified(false), m_is_writing(false), m_did_eject(false) #if __APPLE__ @@ -442,7 +443,6 @@ bool RemovableDriveManager::update(const long time,const bool check) return !m_current_drives.empty(); } - bool RemovableDriveManager::is_drive_mounted(const std::string &path) { for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) @@ -461,12 +461,14 @@ std::string RemovableDriveManager::get_drive_path() reset_last_save_path(); return ""; } - if (m_last_save_path != "") + if (m_last_save_path_verified) return m_last_save_path; return m_current_drives.back().path; } std::string RemovableDriveManager::get_last_save_path() { + if (!m_last_save_path_verified) + return ""; return m_last_save_path; } std::string RemovableDriveManager::get_last_save_name() @@ -481,7 +483,7 @@ void RemovableDriveManager::check_and_notify() { if(m_drives_count != m_current_drives.size()) { - if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path != "" && !is_drive_mounted(m_last_save_path)) + if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path_verified && !is_drive_mounted(m_last_save_path)) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { @@ -501,9 +503,14 @@ void RemovableDriveManager::erase_callbacks() } void RemovableDriveManager::set_last_save_path(const std::string& path) { - std::string last_drive = get_drive_from_path(path); - if(last_drive != "") + m_last_save_path = path; +} +void RemovableDriveManager::verify_last_save_path() +{ + std::string last_drive = get_drive_from_path(m_last_save_path); + if (last_drive != "") { + m_last_save_path_verified = true; m_last_save_path = last_drive; m_last_save_name = get_drive_name(last_drive); } @@ -525,7 +532,7 @@ bool RemovableDriveManager::is_last_drive_removed() { //std::cout<<"is last: "< Date: Tue, 17 Dec 2019 13:08:17 +0100 Subject: [PATCH 114/162] macos device detection --- src/slic3r/CMakeLists.txt | 8 +++ src/slic3r/GUI/RemovableDriveManager.cpp | 2 + src/slic3r/GUI/RemovableDriveManager.hpp | 1 + src/slic3r/GUI/RemovableDriveManagerMM.h | 1 + src/slic3r/GUI/RemovableDriveManagerMM.mm | 86 ++++++++++++++++++++++- 5 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index a06a8cf1d1..5b55b96b4b 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -172,6 +172,9 @@ if (APPLE) GUI/RemovableDriveManagerMM.mm GUI/RemovableDriveManagerMM.h ) + #DK + FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration) + endif () add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) @@ -179,6 +182,11 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) encoding_check(libslic3r_gui) target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi) +#DK +if(APPLE) + target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY}) +endif() + if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) endif () diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 52a8c2b77e..6e13a59b5c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -354,6 +354,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) // but neither triggers "succesful safe removal messege" std::string command = ""; #if __APPLE__ + //m_rdmmm->eject_device(path); command = "diskutil unmount "; #else command = "umount "; @@ -365,6 +366,7 @@ void RemovableDriveManager::eject_drive(const std::string &path) std::cerr<<"Ejecting failed\n"; return; } + m_did_eject = true; m_current_drives.erase(it); diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 2e9fc9f4ef..1b337338e9 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -96,6 +96,7 @@ public: ~RDMMMWrapper(); void register_window(); void list_devices(); + void eject_device(const std::string &path); void log(const std::string &msg); protected: void *m_imp; diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.h b/src/slic3r/GUI/RemovableDriveManagerMM.h index 2999415454..71239dba32 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.h +++ b/src/slic3r/GUI/RemovableDriveManagerMM.h @@ -6,4 +6,5 @@ -(void) add_unmount_observer; -(void) on_device_unmount: (NSNotification*) notification; -(NSArray*) list_dev; +-(void)eject_drive:(NSString *)path; @end diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index 3bb017a3aa..01d38b1855 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -1,6 +1,7 @@ #import "RemovableDriveManager.hpp" #import "RemovableDriveManagerMM.h" #import +#import @implementation RemovableDriveManagerMM @@ -27,9 +28,81 @@ } -(NSArray*) list_dev { - NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; - return devices; + // DEPRICATED: + //NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; + //return devices; + NSArray *mountedRemovableMedia = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes]; + NSMutableArray *result = [NSMutableArray array]; + for(NSURL *volURL in mountedRemovableMedia) + { + int err = 0; + DADiskRef disk; + DASessionRef session; + CFDictionaryRef descDict; + session = DASessionCreate(NULL); + if (session == NULL) { + err = EINVAL; + } + if (err == 0) { + disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)volURL); + if (session == NULL) { + err = EINVAL; + } + } + if (err == 0) { + descDict = DADiskCopyDescription(disk); + if (descDict == NULL) { + err = EINVAL; + } + } + if (err == 0) { + CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey); + BOOL ejectable = [mediaEjectableKey boolValue]; + CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey); + CFTypeRef deviceModelKey = CFDictionaryGetValue(descDict, kDADiskDescriptionDeviceModelKey); + if (mediaEjectableKey != NULL) + { + BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader"))); + //!CFEqual(deviceModelKey, CFSTR("Disk Image")); + // + if (op) { + [result addObject:volURL.path]; + } + } + } + if (descDict != NULL) { + CFRelease(descDict); + } + + + } + return result; +} +-(void)eject_drive:(NSString *)path +{ + DADiskRef disk; + DASessionRef session; + NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; + int err = 0; + session = DASessionCreate(NULL); + if (session == NULL) { + err = EINVAL; + } + if (err == 0) { + disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)url); + } + if( err == 0) + { + DADiskUnmount(disk, kDADiskUnmountOptionDefault, + NULL, NULL); + } + if (disk != NULL) { + CFRelease(disk); + } + if (session != NULL) { + CFRelease(session); + } } namespace Slic3r { namespace GUI { @@ -66,6 +139,15 @@ void RDMMMWrapper::log(const std::string &msg) { NSLog(@"%s", msg.c_str()); } +void RDMMMWrapper::eject_device(const std::string &path) +{ + if(m_imp) + { + NSString * pth = [NSString stringWithCString:path.c_str() + encoding:[NSString defaultCStringEncoding]]; + [m_imp eject_drive:pth]; + } +} }}//namespace Slicer::GUI /* From 7e4e1745afb7ac09c65d3fe6cf7bffbc22eb8b84 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 09:36:26 +0100 Subject: [PATCH 115/162] bug fix - using two devices --- src/slic3r/GUI/RemovableDriveManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 6e13a59b5c..d10447cc66 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -505,6 +505,7 @@ void RemovableDriveManager::erase_callbacks() } void RemovableDriveManager::set_last_save_path(const std::string& path) { + m_last_save_path_verified = false; m_last_save_path = path; } void RemovableDriveManager::verify_last_save_path() From 1404dba81ca9ae35bbe9beb147079795e7e8dd37 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 09:56:38 +0100 Subject: [PATCH 116/162] set_did_eject method --- src/slic3r/GUI/Plater.cpp | 1 + src/slic3r/GUI/RemovableDriveManager.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 523cd2bd31..79ebd28505 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5050,6 +5050,7 @@ void Plater::drive_ejected_callback() { if (RemovableDriveManager::get_instance().get_did_eject()) { + RemovableDriveManager::get_instance().set_did_eject(false); wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer."; wxMessageBox(message); } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index d10447cc66..7a2464351c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -572,4 +572,8 @@ bool RemovableDriveManager::get_did_eject() { return m_did_eject; } +void RemovableDriveManager::set_did_eject(const bool b) +{ + m_did_eject = b; +} }}//namespace Slicer::Gui From 146b94264171180199309275c93e0a8553a135e0 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 10:08:17 +0100 Subject: [PATCH 117/162] set_did_eject method --- src/slic3r/GUI/Plater.cpp | 1 + src/slic3r/GUI/RemovableDriveManager.cpp | 4 ++++ src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 3 files changed, 6 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 523cd2bd31..79ebd28505 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5050,6 +5050,7 @@ void Plater::drive_ejected_callback() { if (RemovableDriveManager::get_instance().get_did_eject()) { + RemovableDriveManager::get_instance().set_did_eject(false); wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer."; wxMessageBox(message); } diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index d10447cc66..7a2464351c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -572,4 +572,8 @@ bool RemovableDriveManager::get_did_eject() { return m_did_eject; } +void RemovableDriveManager::set_did_eject(const bool b) +{ + m_did_eject = b; +} }}//namespace Slicer::Gui diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 1b337338e9..ea4584feee 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -56,6 +56,7 @@ public: void set_is_writing(const bool b); bool get_is_writing(); bool get_did_eject(); + void set_did_eject(const bool b); std::string get_drive_name(const std::string& path); private: RemovableDriveManager(); From 1fa464af9653aa739e814fd8835c7ad52fdc4394 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 10:34:26 +0100 Subject: [PATCH 118/162] removableDriveManager bug fixes --- deps/CGAL/CGAL.cmake | 6 + deps/GMP/GMP.cmake | 2 +- resources/icons/thumb_down.svg | 2 +- resources/icons/thumb_up.svg | 2 +- src/hidapi/CMakeLists.txt | 2 +- src/hidapi/README.md | 5 + src/libslic3r/Format/3mf.cpp | 45 ++-- src/libslic3r/Format/AMF.cpp | 14 +- src/libslic3r/GCode.cpp | 40 ++-- src/libslic3r/GCode.hpp | 2 +- src/libslic3r/GCodeWriter.hpp | 5 + src/libslic3r/Model.cpp | 53 ++++- src/libslic3r/Model.hpp | 31 +-- src/libslic3r/Print.cpp | 4 +- src/libslic3r/PrintConfig.hpp | 6 - src/libslic3r/ShortestPath.cpp | 11 +- src/libslic3r/Slicing.cpp | 98 +++----- src/libslic3r/Slicing.hpp | 14 +- src/libslic3r/SlicingAdaptive.cpp | 246 ++++++++++++-------- src/libslic3r/SlicingAdaptive.hpp | 48 ++-- src/libslic3r/Technologies.hpp | 3 + src/slic3r/GUI/BackgroundSlicingProcess.cpp | 7 +- src/slic3r/GUI/GLCanvas3D.cpp | 72 +++--- src/slic3r/GUI/GLCanvas3D.hpp | 8 +- src/slic3r/GUI/GUI_Preview.cpp | 10 +- src/slic3r/GUI/ImGuiWrapper.cpp | 10 + src/slic3r/GUI/ImGuiWrapper.hpp | 2 + src/slic3r/GUI/Mouse3DController.cpp | 219 +++++++++++------ src/slic3r/GUI/Mouse3DController.hpp | 19 +- src/slic3r/GUI/Plater.cpp | 28 ++- src/slic3r/GUI/PresetBundle.cpp | 4 + src/slic3r/GUI/RemovableDriveManager.cpp | 5 + src/slic3r/GUI/RemovableDriveManager.hpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 42 ++-- src/slic3r/GUI/wxExtensions.hpp | 17 +- version.inc | 6 +- 36 files changed, 620 insertions(+), 469 deletions(-) create mode 100644 src/hidapi/README.md diff --git a/deps/CGAL/CGAL.cmake b/deps/CGAL/CGAL.cmake index 4b127cd512..96a6292580 100644 --- a/deps/CGAL/CGAL.cmake +++ b/deps/CGAL/CGAL.cmake @@ -6,4 +6,10 @@ prusaslicer_add_cmake_project( # URL https://github.com/CGAL/cgal/archive/releases/CGAL-5.0.zip # URL_HASH SHA256=bd9327be903ab7ee379a8a7a0609eba0962f5078d2497cf8e13e8e1598584154 DEPENDS dep_boost dep_GMP dep_MPFR +) + +ExternalProject_Add_Step(dep_CGAL dep_CGAL_relocation_fix + DEPENDEES install + COMMAND ${CMAKE_COMMAND} -E remove CGALConfig-installation-dirs.cmake + WORKING_DIRECTORY "${DESTDIR}/usr/local/lib/cmake/CGAL" ) \ No newline at end of file diff --git a/deps/GMP/GMP.cmake b/deps/GMP/GMP.cmake index 6c93107c42..8bcf948592 100644 --- a/deps/GMP/GMP.cmake +++ b/deps/GMP/GMP.cmake @@ -20,7 +20,7 @@ else () ExternalProject_Add(dep_GMP URL https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2 BUILD_IN_SOURCE ON - CONFIGURE_COMMAND ./configure --enable-shared=no --enable-static=yes "--prefix=${DESTDIR}/usr/local" --with-pic + CONFIGURE_COMMAND ./configure --enable-shared=no --enable-cxx=yes --enable-static=yes "--prefix=${DESTDIR}/usr/local" --with-pic BUILD_COMMAND make -j INSTALL_COMMAND make install ) diff --git a/resources/icons/thumb_down.svg b/resources/icons/thumb_down.svg index 0499cea419..f789b73174 100644 --- a/resources/icons/thumb_down.svg +++ b/resources/icons/thumb_down.svg @@ -4,7 +4,7 @@ viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> - + diff --git a/resources/icons/thumb_up.svg b/resources/icons/thumb_up.svg index c9045929be..1a0c6f1b7f 100644 --- a/resources/icons/thumb_up.svg +++ b/resources/icons/thumb_up.svg @@ -4,7 +4,7 @@ viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> - + diff --git a/src/hidapi/CMakeLists.txt b/src/hidapi/CMakeLists.txt index 1f53c9b692..f3045466e1 100644 --- a/src/hidapi/CMakeLists.txt +++ b/src/hidapi/CMakeLists.txt @@ -15,5 +15,5 @@ add_library(hidapi STATIC ${HIDAPI_IMPL}) if (CMAKE_SYSTEM_NAME STREQUAL "Linux") # Don't link the udev library, as there are two versions out there (libudev.so.0, libudev.so.1), so they are linked explicitely. # target_link_libraries(hidapi udev) - target_link_libraries(hidapi) + target_link_libraries(hidapi dl) endif() diff --git a/src/hidapi/README.md b/src/hidapi/README.md new file mode 100644 index 0000000000..4f66b3274a --- /dev/null +++ b/src/hidapi/README.md @@ -0,0 +1,5 @@ +** hidapi is a c++ library for communicating with USB and Bluetooth HID devices on Linux, Mac and Windows.** + +For more information go to https://github.com/libusb/hidapi + +THIS DIRECTORY CONTAINS THE hidapi-0.9.0 7da5cc9 SOURCE DISTRIBUTION. diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 89e8c0f629..b25d15af58 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -51,7 +51,7 @@ const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config"; const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt"; const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt"; -const std::string CUSTOM_GCODE_PER_HEIGHT_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_height.xml"; +const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml"; const char* MODEL_TAG = "model"; const char* RESOURCES_TAG = "resources"; @@ -418,7 +418,7 @@ namespace Slic3r { void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); - void _extract_custom_gcode_per_height_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); + void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename); bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model); @@ -629,10 +629,10 @@ namespace Slic3r { // extract slic3r print config file _extract_print_config_from_archive(archive, stat, config, filename); } - if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_HEIGHT_FILE)) + if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_PRINT_Z_FILE)) { // extract slic3r layer config ranges file - _extract_custom_gcode_per_height_from_archive(archive, stat); + _extract_custom_gcode_per_print_z_from_archive(archive, stat); } else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE)) { @@ -1064,7 +1064,7 @@ namespace Slic3r { return true; } - void _3MF_Importer::_extract_custom_gcode_per_height_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat) + void _3MF_Importer::_extract_custom_gcode_per_print_z_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat) { if (stat.m_uncomp_size > 0) { @@ -1079,24 +1079,23 @@ namespace Slic3r { pt::ptree main_tree; pt::read_xml(iss, main_tree); - if (main_tree.front().first != "custom_gcodes_per_height") + if (main_tree.front().first != "custom_gcodes_per_print_z") return; pt::ptree code_tree = main_tree.front().second; - if (!m_model->custom_gcode_per_height.empty()) - m_model->custom_gcode_per_height.clear(); + m_model->custom_gcode_per_print_z.clear(); for (const auto& code : code_tree) { if (code.first != "code") continue; pt::ptree tree = code.second; - double height = tree.get(".height"); - std::string gcode = tree.get(".gcode"); - int extruder = tree.get(".extruder"); - std::string color = tree.get(".color"); + double print_z = tree.get (".print_z" ); + std::string gcode = tree.get (".gcode" ); + int extruder = tree.get (".extruder" ); + std::string color = tree.get (".color" ); - m_model->custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color)) ; + m_model->custom_gcode_per_print_z.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ; } } } @@ -1885,7 +1884,7 @@ namespace Slic3r { bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config); bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data); - bool _add_custom_gcode_per_height_file_to_archive(mz_zip_archive& archive, Model& model); + bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model); }; #if ENABLE_THUMBNAIL_GENERATOR @@ -1988,9 +1987,9 @@ namespace Slic3r { return false; } - // Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_height.xml"). + // Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml"). // All custom gcode per height of whole Model are stored here - if (!_add_custom_gcode_per_height_file_to_archive(archive, model)) + if (!_add_custom_gcode_per_print_z_file_to_archive(archive, model)) { close_zip_writer(&archive); boost::filesystem::remove(filename); @@ -2567,20 +2566,20 @@ namespace Slic3r { return true; } -bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive& archive, Model& model) +bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archive& archive, Model& model) { std::string out = ""; - if (!model.custom_gcode_per_height.empty()) + if (!model.custom_gcode_per_print_z.empty()) { pt::ptree tree; - pt::ptree& main_tree = tree.add("custom_gcodes_per_height", ""); + pt::ptree& main_tree = tree.add("custom_gcodes_per_print_z", ""); - for (const Model::CustomGCode& code : model.custom_gcode_per_height) + for (const Model::CustomGCode& code : model.custom_gcode_per_print_z) { pt::ptree& code_tree = main_tree.add("code", ""); // store minX and maxZ - code_tree.put(".height" , code.height ); + code_tree.put(".print_z" , code.print_z ); code_tree.put(".gcode" , code.gcode ); code_tree.put(".extruder" , code.extruder ); code_tree.put(".color" , code.color ); @@ -2599,9 +2598,9 @@ bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive if (!out.empty()) { - if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_HEIGHT_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) + if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { - add_error("Unable to add custom Gcodes per height file to archive"); + add_error("Unable to add custom Gcodes per print_z file to archive"); return false; } } diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index d50f6e395c..aee8b74018 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -637,7 +637,7 @@ void AMFParserContext::endElement(const char * /* name */) int extruder = atoi(m_value[2].c_str()); const std::string& color = m_value[3]; - m_model.custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color)); + m_model.custom_gcode_per_print_z.push_back(Model::CustomGCode{height, gcode, extruder, color}); for (std::string& val: m_value) val.clear(); @@ -1221,21 +1221,21 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " \n"; } - if (!model->custom_gcode_per_height.empty()) + if (!model->custom_gcode_per_print_z.empty()) { std::string out = ""; pt::ptree tree; pt::ptree& main_tree = tree.add("custom_gcodes_per_height", ""); - for (const Model::CustomGCode& code : model->custom_gcode_per_height) + for (const Model::CustomGCode& code : model->custom_gcode_per_print_z) { pt::ptree& code_tree = main_tree.add("code", ""); // store minX and maxZ - code_tree.put(".height", code.height); - code_tree.put(".gcode", code.gcode); - code_tree.put(".extruder", code.extruder); - code_tree.put(".color", code.color); + code_tree.put(".print_z" , code.print_z ); + code_tree.put(".gcode" , code.gcode ); + code_tree.put(".extruder" , code.extruder ); + code_tree.put(".color" , code.color ); } if (!tree.empty()) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 91627631f4..433422d997 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -936,7 +936,7 @@ void GCode::_do_export(Print& print, FILE* file) // Initialize custom gcode Model* model = print.get_object(0)->model_object()->get_model(); - m_custom_g_code_heights = model->custom_gcode_per_height; + m_custom_gcode_per_print_z = model->custom_gcode_per_print_z; // Initialize autospeed. { @@ -1124,20 +1124,22 @@ void GCode::_do_export(Print& print, FILE* file) } print.throw_if_canceled(); +// #ys_FIXME_no_exported_codes + /* /* To avoid change filament for non-used extruder for Multi-material, - * check model->custom_gcode_per_height using tool_ordering values - * */ - if (!m_custom_g_code_heights. empty()) + * check model->custom_gcode_per_print_z using tool_ordering values + * / + if (!m_custom_gcode_per_print_z. empty()) { bool delete_executed = false; - auto it = m_custom_g_code_heights.end(); - while (it != m_custom_g_code_heights.begin()) + auto it = m_custom_gcode_per_print_z.end(); + while (it != m_custom_gcode_per_print_z.begin()) { --it; if (it->gcode != ColorChangeCode) continue; - auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->height)); + auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->print_z)); bool used_extruder = false; for (; it_layer_tools != tool_ordering.end(); it_layer_tools++) @@ -1154,16 +1156,16 @@ void GCode::_do_export(Print& print, FILE* file) /* If we are there, current extruder wouldn't be used, * so this color change is a redundant move. - * Delete this item from m_custom_g_code_heights - * */ - it = m_custom_g_code_heights.erase(it); + * Delete this item from m_custom_gcode_per_print_z + * / + it = m_custom_gcode_per_print_z.erase(it); delete_executed = true; } if (delete_executed) - model->custom_gcode_per_height = m_custom_g_code_heights; + model->custom_gcode_per_print_z = m_custom_gcode_per_print_z; } - +*/ m_cooling_buffer->set_current_extruder(initial_extruder_id); @@ -1461,7 +1463,7 @@ void GCode::_do_export(Print& print, FILE* file) dst.first += buf; ++ dst.second; }; - print.m_print_statistics.filament_stats.insert(std::pair(extruder.id(), (float)used_filament)); + print.m_print_statistics.filament_stats.insert(std::pair{extruder.id(), (float)used_filament}); append(out_filament_used_mm, "%.1lf", used_filament); append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001); if (filament_weight > 0.) { @@ -1835,15 +1837,15 @@ void GCode::process_layer( std::string custom_code = ""; std::string pause_print_msg = ""; int m600_before_extruder = -1; - while (!m_custom_g_code_heights.empty() && m_custom_g_code_heights.front().height-EPSILON < layer.print_z) { - custom_code = m_custom_g_code_heights.front().gcode; + while (!m_custom_gcode_per_print_z.empty() && m_custom_gcode_per_print_z.front().print_z - EPSILON < layer.print_z) { + custom_code = m_custom_gcode_per_print_z.front().gcode; - if (custom_code == ColorChangeCode && m_custom_g_code_heights.front().extruder > 0) - m600_before_extruder = m_custom_g_code_heights.front().extruder - 1; + if (custom_code == ColorChangeCode && m_custom_gcode_per_print_z.front().extruder > 0) + m600_before_extruder = m_custom_gcode_per_print_z.front().extruder - 1; if (custom_code == PausePrintCode) - pause_print_msg = m_custom_g_code_heights.front().color; + pause_print_msg = m_custom_gcode_per_print_z.front().color; - m_custom_g_code_heights.erase(m_custom_g_code_heights.begin()); + m_custom_gcode_per_print_z.erase(m_custom_gcode_per_print_z.begin()); colorprint_change = true; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 7f009b8147..68bb85a988 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -367,7 +367,7 @@ protected: * Updated before the export and erased during the process, * so no toolchange occurs twice. * */ - std::vector m_custom_g_code_heights; + std::vector m_custom_gcode_per_print_z; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 664b0e3a1d..98abdda280 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -10,6 +10,11 @@ namespace Slic3r { +// Additional Codes which can be set by user using DoubleSlider +static constexpr char ColorChangeCode[] = "M600"; +static constexpr char PausePrintCode[] = "M601"; +static constexpr char ExtruderChangeCode[] = "tool_change"; + class GCodeWriter { public: GCodeConfig config; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ce3debfb52..7137527e9f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -18,6 +18,8 @@ #include "SVG.hpp" #include +#include "GCodeWriter.hpp" +#include "GCode/PreviewData.hpp" namespace Slic3r { @@ -43,7 +45,7 @@ Model& Model::assign_copy(const Model &rhs) } // copy custom code per height - this->custom_gcode_per_height = rhs.custom_gcode_per_height; + this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z; return *this; } @@ -64,7 +66,7 @@ Model& Model::assign_copy(Model &&rhs) rhs.objects.clear(); // copy custom code per height - this->custom_gcode_per_height = rhs.custom_gcode_per_height; + this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z; return *this; } @@ -124,6 +126,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c if (add_default_instances) model.add_default_instances(); + update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config); + return model; } @@ -159,6 +163,8 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig if (add_default_instances) model.add_default_instances(); + update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config); + return model; } @@ -595,16 +601,15 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte std::vector> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const { std::vector> custom_tool_changes; - if (!custom_gcode_per_height.empty()) { - for (const CustomGCode& custom_gcode : custom_gcode_per_height) - if (custom_gcode.gcode == ExtruderChangeCode) { - DynamicPrintConfig config; - // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders - config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder)); - // For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height - custom_tool_changes.push_back({ custom_gcode.height - default_layer_height, config }); - } - } + for (const CustomGCode& custom_gcode : custom_gcode_per_print_z) + if (custom_gcode.gcode == ExtruderChangeCode) { + DynamicPrintConfig config; + // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders + config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder)); + // For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height + custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config }); + } + return custom_tool_changes; } @@ -1933,6 +1938,30 @@ extern bool model_has_advanced_features(const Model &model) return false; } +extern void update_custom_gcode_per_print_z_from_config(std::vector& custom_gcode_per_print_z, DynamicPrintConfig* config) +{ + if (!config->has("colorprint_heights")) + return; + + const std::vector& colors = GCodePreviewData::ColorPrintColors(); + + const auto& colorprint_values = config->option("colorprint_heights")->values; + + if (!colorprint_values.empty()) + { + custom_gcode_per_print_z.clear(); + custom_gcode_per_print_z.reserve(colorprint_values.size()); + int i = 0; + for (auto val : colorprint_values) + custom_gcode_per_print_z.emplace_back(Model::CustomGCode{ val, ColorChangeCode, 1, colors[(++i)%7] }); + } + + /* There is one and only place this configuration option is used now. + * It wouldn't be used in the future, so erase it. + * */ + config->erase("colorprint_heights"); +} + #ifndef NDEBUG // Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique. void check_model_ids_validity(const Model &model) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index c2942a4ea3..9f173f6ea0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -749,33 +749,30 @@ public: // Extensions for color print struct CustomGCode { - CustomGCode(double height, const std::string& code, int extruder, const std::string& color) : - height(height), gcode(code), extruder(extruder), color(color) {} - - bool operator<(const CustomGCode& other) const { return other.height > this->height; } + bool operator<(const CustomGCode& other) const { return other.print_z > this->print_z; } bool operator==(const CustomGCode& other) const { - return (other.height == this->height) && - (other.gcode == this->gcode) && - (other.extruder == this->extruder )&& - (other.color == this->color ); + return (other.print_z == this->print_z ) && + (other.gcode == this->gcode ) && + (other.extruder == this->extruder ) && + (other.color == this->color ); } bool operator!=(const CustomGCode& other) const { - return (other.height != this->height) || - (other.gcode != this->gcode) || - (other.extruder != this->extruder )|| - (other.color != this->color ); + return (other.print_z != this->print_z ) || + (other.gcode != this->gcode ) || + (other.extruder != this->extruder ) || + (other.color != this->color ); } - double height; + double print_z; std::string gcode; int extruder; // 0 - "gcode" will be applied for whole print // else - "gcode" will be applied only for "extruder" print std::string color; // if gcode is equal to PausePrintCode, // this field is used for save a short message shown on Printer display }; - std::vector custom_gcode_per_height; + std::vector custom_gcode_per_print_z; // Default constructor assigns a new ID to the model. Model() { assert(this->id().valid()); } @@ -841,7 +838,7 @@ public: // Propose an output path, replace extension. The new_extension shall contain the initial dot. std::string propose_export_file_name_and_path(const std::string &new_extension) const; - // from custom_gcode_per_height get just tool_change codes + // from custom_gcode_per_print_z get just tool_change codes std::vector> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const; private: @@ -877,6 +874,10 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const extern bool model_has_multi_part_objects(const Model &model); // If the model has advanced features, then it cannot be processed in simple mode. extern bool model_has_advanced_features(const Model &model); +/* If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer), + * then model.custom_gcode_per_print_z should be updated considering this option + * */ +extern void update_custom_gcode_per_print_z_from_config(std::vector& custom_gcode_per_print_z, DynamicPrintConfig* config); #ifndef NDEBUG // Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ae32bd2d37..1d4e69763e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -739,10 +739,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); // But if custom gcode per layer height was changed - if (m_model.custom_gcode_per_height != model.custom_gcode_per_height) { + if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) { // we should stop background processing update_apply_status(this->invalidate_step(psGCodeExport)); - m_model.custom_gcode_per_height = model.custom_gcode_per_height; + m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z; } } else if (model_object_list_extended(m_model, model)) { // Add new objects. Their volumes and configs will be synchronized later. diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 9f3bc05391..5f5a861da3 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -71,12 +71,6 @@ enum SLAPillarConnectionMode { slapcmDynamic }; -// ys_FIXME ! may be, it's not a best place -// Additional Codes which can be set by user using DoubleSlider -static const std::string ColorChangeCode = "M600"; -static const std::string PausePrintCode = "M601"; -static const std::string ExtruderChangeCode = "tool_change"; - template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index 8b5cbf483c..e9df4c5b5c 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -43,6 +43,7 @@ std::vector> chain_segments_closest_point(std::vector> chain_segments_greedy_constrained_reversals else if (num_segments == 1) { // Just sort the end points so that the first point visited is closest to start_near. - out.emplace_back(0, start_near != nullptr && + out.emplace_back(0, could_reverse_func(0) && start_near != nullptr && (end_point_func(0, true) - *start_near).template cast().squaredNorm() < (end_point_func(0, false) - *start_near).template cast().squaredNorm()); } else @@ -999,13 +1000,13 @@ std::vector> chain_extrusion_entities(std::vector const Point& { return first_point ? entities[idx]->first_point() : entities[idx]->last_point(); }; auto could_reverse = [&entities](size_t idx) { const ExtrusionEntity *ee = entities[idx]; return ee->is_loop() || ee->can_reverse(); }; std::vector> out = chain_segments_greedy_constrained_reversals(segment_end_point, could_reverse, entities.size(), start_near); - for (size_t i = 0; i < entities.size(); ++ i) { - ExtrusionEntity *ee = entities[i]; + for (std::pair &segment : out) { + ExtrusionEntity *ee = entities[segment.first]; if (ee->is_loop()) // Ignore reversals for loops, as the start point equals the end point. - out[i].second = false; + segment.second = false; // Is can_reverse() respected by the reversals? - assert(entities[i]->can_reverse() || ! out[i].second); + assert(ee->can_reverse() || ! segment.second); } return out; } diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 9af6048abf..8199bde031 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -224,38 +224,14 @@ std::vector layer_height_profile_from_ranges( // Based on the work of @platsch // Fill layer_height_profile by heights ensuring a prescribed maximum cusp height. -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -std::vector layer_height_profile_adaptive(const SlicingParameters& slicing_params, - const ModelObject& object, float cusp_value) -#else -std::vector layer_height_profile_adaptive( - const SlicingParameters &slicing_params, - const t_layer_config_ranges & /* layer_config_ranges */, - const ModelVolumePtrs &volumes) -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +std::vector layer_height_profile_adaptive(const SlicingParameters& slicing_params, const ModelObject& object, float quality_factor) { -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // 1) Initialize the SlicingAdaptive class with the object meshes. SlicingAdaptive as; as.set_slicing_parameters(slicing_params); - as.set_object(object); -#else - // 1) Initialize the SlicingAdaptive class with the object meshes. - SlicingAdaptive as; - as.set_slicing_parameters(slicing_params); - for (const ModelVolume* volume : volumes) - if (volume->is_model_part()) - as.add_mesh(&volume->mesh()); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - - as.prepare(); + as.prepare(object); // 2) Generate layers using the algorithm of @platsch - // loop until we have at least one layer and the max slice_z reaches the object height -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - double cusp_value = 0.2; -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - std::vector layer_height_profile; layer_height_profile.push_back(0.0); layer_height_profile.push_back(slicing_params.first_object_layer_height); @@ -263,39 +239,41 @@ std::vector layer_height_profile_adaptive( layer_height_profile.push_back(slicing_params.first_object_layer_height); layer_height_profile.push_back(slicing_params.first_object_layer_height); } - double slice_z = slicing_params.first_object_layer_height; - int current_facet = 0; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - while (slice_z <= slicing_params.object_print_z_height()) { - double height = slicing_params.max_layer_height; -#else - double height = slicing_params.first_object_layer_height; - while ((slice_z - height) <= slicing_params.object_print_z_height()) { - height = 999.0; -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + double print_z = slicing_params.first_object_layer_height; + // last facet visited by the as.next_layer_height() function, where the facets are sorted by their increasing Z span. + size_t current_facet = 0; + // loop until we have at least one layer and the max slice_z reaches the object height + while (print_z + EPSILON < slicing_params.object_print_z_height()) { + float height = slicing_params.max_layer_height; // Slic3r::debugf "\n Slice layer: %d\n", $id; // determine next layer height - double cusp_height = as.cusp_height((float)slice_z, cusp_value, current_facet); + float cusp_height = as.next_layer_height(float(print_z), quality_factor, current_facet); +#if 0 // check for horizontal features and object size - /* - if($self->config->get_value('match_horizontal_surfaces')) { - my $horizontal_dist = $adaptive_slicing[$region_id]->horizontal_facet_distance(scale $slice_z+$cusp_height, $min_height); - if(($horizontal_dist < $min_height) && ($horizontal_dist > 0)) { - Slic3r::debugf "Horizontal feature ahead, distance: %f\n", $horizontal_dist; - # can we shrink the current layer a bit? - if($cusp_height-($min_height-$horizontal_dist) > $min_height) { - # yes we can - $cusp_height = $cusp_height-($min_height-$horizontal_dist); - Slic3r::debugf "Shrink layer height to %f\n", $cusp_height; - }else{ - # no, current layer would become too thin - $cusp_height = $cusp_height+$horizontal_dist; - Slic3r::debugf "Widen layer height to %f\n", $cusp_height; + if (this->config.match_horizontal_surfaces.value) { + coordf_t horizontal_dist = as.horizontal_facet_distance(print_z + height, min_layer_height); + if ((horizontal_dist < min_layer_height) && (horizontal_dist > 0)) { + #ifdef SLIC3R_DEBUG + std::cout << "Horizontal feature ahead, distance: " << horizontal_dist << std::endl; + #endif + // can we shrink the current layer a bit? + if (height-(min_layer_height - horizontal_dist) > min_layer_height) { + // yes we can + height -= (min_layer_height - horizontal_dist); + #ifdef SLIC3R_DEBUG + std::cout << "Shrink layer height to " << height << std::endl; + #endif + } else { + // no, current layer would become too thin + height += horizontal_dist; + #ifdef SLIC3R_DEBUG + std::cout << "Widen layer height to " << height << std::endl; + #endif } } } - */ +#endif height = std::min(cusp_height, height); // apply z-gradation @@ -308,22 +286,22 @@ std::vector layer_height_profile_adaptive( // look for an applicable custom range /* - if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) { + if (my $range = first { $_->[0] <= $print_z && $_->[1] > $print_z } @{$self->layer_height_ranges}) { $height = $range->[2]; # if user set custom height to zero we should just skip the range and resume slicing over it if ($height == 0) { - $slice_z += $range->[1] - $range->[0]; + $print_z += $range->[1] - $range->[0]; next; } } */ - layer_height_profile.push_back(slice_z); + layer_height_profile.push_back(print_z); layer_height_profile.push_back(height); - slice_z += height; + print_z += height; #if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - layer_height_profile.push_back(slice_z); + layer_height_profile.push_back(print_z); layer_height_profile.push_back(height); #endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } @@ -722,11 +700,7 @@ int generate_layer_height_texture( const Vec3crd &color1 = palette_raw[idx1]; const Vec3crd &color2 = palette_raw[idx2]; coordf_t z = cell_to_z * coordf_t(cell); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - assert((lo - EPSILON <= z) && (z <= hi + EPSILON)); -#else - assert(z >= lo && z <= hi); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + assert(lo - EPSILON <= z && z <= hi + EPSILON); // Intensity profile to visualize the layers. coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h); // Color mapping from layer height to RGB. diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index 03ef7e67d6..036344b224 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -18,12 +18,7 @@ namespace Slic3r class PrintConfig; class PrintObjectConfig; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class ModelObject; -#else -class ModelVolume; -typedef std::vector ModelVolumePtrs; -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Parameters to guide object slicing and support generation. // The slicing parameters account for a raft and whether the 1st object layer is printed with a normal or a bridging flow @@ -142,10 +137,9 @@ extern std::vector layer_height_profile_from_ranges( const SlicingParameters &slicing_params, const t_layer_config_ranges &layer_config_ranges); -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE extern std::vector layer_height_profile_adaptive( const SlicingParameters& slicing_params, - const ModelObject& object, float cusp_value); + const ModelObject& object, float quality_factor); struct HeightProfileSmoothingParams { @@ -159,12 +153,6 @@ struct HeightProfileSmoothingParams extern std::vector smooth_height_profile( const std::vector& profile, const SlicingParameters& slicing_params, const HeightProfileSmoothingParams& smoothing_params); -#else -extern std::vector layer_height_profile_adaptive( - const SlicingParameters &slicing_params, - const t_layer_config_ranges &layer_config_ranges, - const ModelVolumePtrs &volumes); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE enum LayerHeightEditActionType : unsigned int { LAYER_HEIGHT_EDIT_ACTION_INCREASE = 0, diff --git a/src/libslic3r/SlicingAdaptive.cpp b/src/libslic3r/SlicingAdaptive.cpp index b6ebf1ac09..7ab0c47b27 100644 --- a/src/libslic3r/SlicingAdaptive.cpp +++ b/src/libslic3r/SlicingAdaptive.cpp @@ -1,156 +1,211 @@ #include "libslic3r.h" -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE #include "Model.hpp" -#else #include "TriangleMesh.hpp" -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE #include "SlicingAdaptive.hpp" +#include + +// Based on the work of Florens Waserfall (@platch on github) +// and his paper +// Florens Wasserfall, Norman Hendrich, Jianwei Zhang: +// Adaptive Slicing for the FDM Process Revisited +// 13th IEEE Conference on Automation Science and Engineering (CASE-2017), August 20-23, Xi'an, China. DOI: 10.1109/COASE.2017.8256074 +// https://tams.informatik.uni-hamburg.de/publications/2017/Adaptive%20Slicing%20for%20the%20FDM%20Process%20Revisited.pdf + +// Vojtech believes that there is a bug in @platch's derivation of the triangle area error metric. +// Following Octave code paints graphs of recommended layer height versus surface slope angle. +#if 0 +adeg=0:1:85; +a=adeg*pi/180; +t=tan(a); +tsqr=sqrt(tan(a)); +lerr=1./cos(a); +lerr2=1./(0.3+cos(a)); +plot(adeg, t, 'b', adeg, sqrt(t), 'g', adeg, 0.5 * lerr, 'm', adeg, 0.5 * lerr2, 'r') +xlabel("angle(deg), 0 - horizontal wall, 90 - vertical wall"); +ylabel("layer height"); +legend("tan(a) as cura - topographic lines distance limit", "sqrt(tan(a)) as PrusaSlicer - error triangle area limit", "old slic3r - max distance metric", "new slic3r - Waserfall paper"); +#endif + +#ifndef NDEBUG + #define ADAPTIVE_LAYER_HEIGHT_DEBUG +#endif /* NDEBUG */ + namespace Slic3r { -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -void SlicingAdaptive::clear() -{ - m_meshes.clear(); - m_faces.clear(); - m_face_normal_z.clear(); -} -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - -std::pair face_z_span(const stl_facet *f) +static inline std::pair face_z_span(const stl_facet &f) { return std::pair( - std::min(std::min(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)), - std::max(std::max(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2))); + std::min(std::min(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2)), + std::max(std::max(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2))); } -void SlicingAdaptive::prepare() +// By Florens Waserfall aka @platch: +// This constant essentially describes the volumetric error at the surface which is induced +// by stacking "elliptic" extrusion threads. It is empirically determined by +// 1. measuring the surface profile of printed parts to find +// the ratio between layer height and profile height and then +// 2. computing the geometric difference between the model-surface and the elliptic profile. +// +// The definition of the roughness formula is in +// https://tams.informatik.uni-hamburg.de/publications/2017/Adaptive%20Slicing%20for%20the%20FDM%20Process%20Revisited.pdf +// (page 51, formula (8)) +// Currenty @platch's error metric formula is not used. +static constexpr double SURFACE_CONST = 0.18403; + +// for a given facet, compute maximum height within the allowed surface roughness / stairstepping deviation +static inline float layer_height_from_slope(const SlicingAdaptive::FaceZ &face, float max_surface_deviation) { -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - if (m_object == nullptr) - return; +// @platch's formula, see his paper "Adaptive Slicing for the FDM Process Revisited". +// return float(max_surface_deviation / (SURFACE_CONST + 0.5 * std::abs(normal_z))); + +// Constant stepping in horizontal direction, as used by Cura. +// return (face.n_cos > 1e-5) ? float(max_surface_deviation * face.n_sin / face.n_cos) : FLT_MAX; - m_faces.clear(); - m_face_normal_z.clear(); +// Constant error measured as an area of the surface error triangle, Vojtech's formula. +// return (face.n_cos > 1e-5) ? float(1.44 * max_surface_deviation * sqrt(face.n_sin / face.n_cos)) : FLT_MAX; - m_mesh = m_object->raw_mesh(); - const ModelInstance* first_instance = m_object->instances.front(); - m_mesh.transform(first_instance->get_matrix(), first_instance->is_left_handed()); +// Constant error measured as an area of the surface error triangle, Vojtech's formula with clamping to roughness at 90 degrees. + return std::min(max_surface_deviation / 0.184f, (face.n_cos > 1e-5) ? float(1.44 * max_surface_deviation * sqrt(face.n_sin / face.n_cos)) : FLT_MAX); + +// Constant stepping along the surface, equivalent to the "surface roughness" metric by Perez and later Pandey et all, see @platch's paper for references. +// return float(max_surface_deviation * face.n_sin); +} + +void SlicingAdaptive::clear() +{ + m_faces.clear(); +} + +void SlicingAdaptive::prepare(const ModelObject &object) +{ + this->clear(); + + TriangleMesh mesh = object.raw_mesh(); + const ModelInstance &first_instance = *object.instances.front(); + mesh.transform(first_instance.get_matrix(), first_instance.is_left_handed()); // 1) Collect faces from mesh. - m_faces.reserve(m_mesh.stl.stats.number_of_facets); - for (stl_facet& face : m_mesh.stl.facet_start) - { - face.normal.normalize(); - m_faces.emplace_back(&face); + m_faces.reserve(mesh.stl.stats.number_of_facets); + for (const stl_facet &face : mesh.stl.facet_start) { + Vec3f n = face.normal.normalized(); + m_faces.emplace_back(FaceZ({ face_z_span(face), std::abs(n.z()), std::sqrt(n.x() * n.x() + n.y() * n.y()) })); } -#else - // 1) Collect faces of all meshes. - int nfaces_total = 0; - for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) - nfaces_total += (*it_mesh)->stl.stats.number_of_facets; - m_faces.reserve(nfaces_total); - for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) - for (const stl_facet& face : (*it_mesh)->stl.facet_start) - m_faces.emplace_back(&face); -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // 2) Sort faces lexicographically by their Z span. - std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) { return face_z_span(f1) < face_z_span(f2); }); - - // 3) Generate Z components of the facet normals. - m_face_normal_z.assign(m_faces.size(), 0.0f); - for (size_t iface = 0; iface < m_faces.size(); ++ iface) - m_face_normal_z[iface] = m_faces[iface]->normal(2); + std::sort(m_faces.begin(), m_faces.end(), [](const FaceZ &f1, const FaceZ &f2) { return f1.z_span < f2.z_span; }); } -float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet) +// current_facet is in/out parameter, rememebers the index of the last face of m_faces visited, +// where this function will start from. +// print_z - the top print surface of the previous layer. +// returns height of the next layer. +float SlicingAdaptive::next_layer_height(const float print_z, float quality_factor, size_t ¤t_facet) { - float height = (float)m_slicing_params.max_layer_height; - bool first_hit = false; + float height = (float)m_slicing_params.max_layer_height; + + float max_surface_deviation; + + { +#if 0 +// @platch's formula for quality: + double delta_min = SURFACE_CONST * m_slicing_params.min_layer_height; + double delta_mid = (SURFACE_CONST + 0.5) * m_slicing_params.layer_height; + double delta_max = (SURFACE_CONST + 0.5) * m_slicing_params.max_layer_height; +#else +// Vojtech's formula for triangle area error metric. + double delta_min = m_slicing_params.min_layer_height; + double delta_mid = m_slicing_params.layer_height; + double delta_max = m_slicing_params.max_layer_height; +#endif + max_surface_deviation = (quality_factor < 0.5f) ? + lerp(delta_min, delta_mid, 2. * quality_factor) : + lerp(delta_max, delta_mid, 2. * (1. - quality_factor)); + } // find all facets intersecting the slice-layer - int ordered_id = current_facet; - for (; ordered_id < int(m_faces.size()); ++ ordered_id) { - std::pair zspan = face_z_span(m_faces[ordered_id]); - // facet's minimum is higher than slice_z -> end loop - if (zspan.first >= z) - break; - // facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point - if (zspan.second > z) { - // first event? - if (! first_hit) { - first_hit = true; - current_facet = ordered_id; - } - // skip touching facets which could otherwise cause small cusp values - if (zspan.second <= z + EPSILON) - continue; - // compute cusp-height for this facet and store minimum of all heights - float normal_z = m_face_normal_z[ordered_id]; - height = std::min(height, (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z)); - } + size_t ordered_id = current_facet; + { + bool first_hit = false; + for (; ordered_id < m_faces.size(); ++ ordered_id) { + const std::pair &zspan = m_faces[ordered_id].z_span; + // facet's minimum is higher than slice_z -> end loop + if (zspan.first >= print_z) + break; + // facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point + if (zspan.second > print_z) { + // first event? + if (! first_hit) { + first_hit = true; + current_facet = ordered_id; + } + // skip touching facets which could otherwise cause small cusp values + if (zspan.second < print_z + EPSILON) + continue; + // compute cusp-height for this facet and store minimum of all heights + height = std::min(height, layer_height_from_slope(m_faces[ordered_id], max_surface_deviation)); + } + } } // lower height limit due to printer capabilities height = std::max(height, float(m_slicing_params.min_layer_height)); // check for sloped facets inside the determined layer and correct height if necessary - if (height > m_slicing_params.min_layer_height) { - for (; ordered_id < int(m_faces.size()); ++ ordered_id) { - std::pair zspan = face_z_span(m_faces[ordered_id]); + if (height > float(m_slicing_params.min_layer_height)) { + for (; ordered_id < m_faces.size(); ++ ordered_id) { + const std::pair &zspan = m_faces[ordered_id].z_span; // facet's minimum is higher than slice_z + height -> end loop - if (zspan.first >= z + height) + if (zspan.first >= print_z + height) break; // skip touching facets which could otherwise cause small cusp values - if (zspan.second <= z + EPSILON) + if (zspan.second < print_z + EPSILON) continue; // Compute cusp-height for this facet and check against height. - float normal_z = m_face_normal_z[ordered_id]; - float cusp = (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z); + float reduced_height = layer_height_from_slope(m_faces[ordered_id], max_surface_deviation); - float z_diff = zspan.first - z; - - // handle horizontal facets - if (normal_z > 0.999f) { - // Slic3r::debugf "cusp computation, height is reduced from %f", $height; + float z_diff = zspan.first - print_z; + if (reduced_height < z_diff) { + assert(z_diff < height + EPSILON); + // The currently visited triangle's slope limits the next layer height so much, that + // the lowest point of the currently visible triangle is already above the newly proposed layer height. + // This means, that we need to limit the layer height so that the offending newly visited triangle + // is just above of the new layer. +#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG + BOOST_LOG_TRIVIAL(trace) << "cusp computation, height is reduced from " << height << "to " << z_diff << " due to z-diff"; +#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */ height = z_diff; - // Slic3r::debugf "to %f due to near horizontal facet\n", $height; - } else if (cusp > z_diff) { - if (cusp < height) { - // Slic3r::debugf "cusp computation, height is reduced from %f", $height; - height = cusp; - // Slic3r::debugf "to %f due to new cusp height\n", $height; - } - } else { - // Slic3r::debugf "cusp computation, height is reduced from %f", $height; - height = z_diff; - // Slic3r::debugf "to z-diff: %f\n", $height; + } else if (reduced_height < height) { +#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG + BOOST_LOG_TRIVIAL(trace) << "adaptive layer computation: height is reduced from " << height << "to " << reduced_height << " due to higher facet"; +#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */ + height = reduced_height; } } // lower height limit due to printer capabilities again height = std::max(height, float(m_slicing_params.min_layer_height)); } -// Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height; +#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG + BOOST_LOG_TRIVIAL(trace) << "adaptive layer computation, layer-bottom at z:" << print_z << ", quality_factor:" << quality_factor << ", resulting layer height:" << height; +#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */ return height; } -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Returns the distance to the next horizontal facet in Z-dir // to consider horizontal object features in slice thickness float SlicingAdaptive::horizontal_facet_distance(float z) { for (size_t i = 0; i < m_faces.size(); ++ i) { - std::pair zspan = face_z_span(m_faces[i]); + std::pair zspan = m_faces[i].z_span; // facet's minimum is higher than max forward distance -> end loop if (zspan.first > z + m_slicing_params.max_layer_height) break; // min_z == max_z -> horizontal facet - if ((zspan.first > z) && (zspan.first == zspan.second)) + if (zspan.first > z && zspan.first == zspan.second) return zspan.first - z; } @@ -158,6 +213,5 @@ float SlicingAdaptive::horizontal_facet_distance(float z) return (z + (float)m_slicing_params.max_layer_height > (float)m_slicing_params.object_print_z_height()) ? std::max((float)m_slicing_params.object_print_z_height() - z, 0.f) : (float)m_slicing_params.max_layer_height; } -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE }; // namespace Slic3r diff --git a/src/libslic3r/SlicingAdaptive.hpp b/src/libslic3r/SlicingAdaptive.hpp index 1d2996986f..a296553d62 100644 --- a/src/libslic3r/SlicingAdaptive.hpp +++ b/src/libslic3r/SlicingAdaptive.hpp @@ -5,50 +5,36 @@ #include "Slicing.hpp" #include "admesh/stl.h" -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -#include "TriangleMesh.hpp" -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE namespace Slic3r { -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class ModelVolume; -#else -class TriangleMesh; -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class SlicingAdaptive { public: -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void clear(); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; } -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void set_object(const ModelObject& object) { m_object = &object; } -#else - void add_mesh(const TriangleMesh* mesh) { m_meshes.push_back(mesh); } -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void prepare(); - float cusp_height(float z, float cusp_value, int ¤t_facet); -#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void clear(); + void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; } + void prepare(const ModelObject &object); + // Return next layer height starting from the last print_z, using a quality measure + // (quality in range from 0 to 1, 0 - highest quality at low layer heights, 1 - lowest print quality at high layer heights). + // The layer height curve shall be centered roughly around the default profile's layer height for quality 0.5. + float next_layer_height(const float print_z, float quality, size_t ¤t_facet); float horizontal_facet_distance(float z); -#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + + struct FaceZ { + std::pair z_span; + // Cosine of the normal vector towards the Z axis. + float n_cos; + // Sine of the normal vector towards the Z axis. + float n_sin; + }; protected: - SlicingParameters m_slicing_params; + SlicingParameters m_slicing_params; -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - const ModelObject* m_object; - TriangleMesh m_mesh; -#else - std::vector m_meshes; -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - // Collected faces of all meshes, sorted by raising Z of the bottom most face. - std::vector m_faces; - // Z component of face normals, normalized. - std::vector m_face_normal_z; + std::vector m_faces; }; }; // namespace Slic3r diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 0ec8b36ee3..d503f0c64a 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -53,4 +53,7 @@ // Enable selection for missing files in reload from disk command #define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1) +// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons +#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1) + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index e587509ac7..a8b88dd037 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -94,12 +94,13 @@ void BackgroundSlicingProcess::process_fff() m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data); #endif // ENABLE_THUMBNAIL_GENERATOR - if (m_fff_print->model().custom_gcode_per_height != GUI::wxGetApp().model().custom_gcode_per_height) { - GUI::wxGetApp().model().custom_gcode_per_height = m_fff_print->model().custom_gcode_per_height; - // #ys_FIXME : controll text + /* #ys_FIXME_no_exported_codes + if (m_fff_print->model().custom_gcode_per_print_z != GUI::wxGetApp().model().custom_gcode_per_print_z) { + GUI::wxGetApp().model().custom_gcode_per_print_z = m_fff_print->model().custom_gcode_per_print_z; GUI::show_info(nullptr, _(L("To except of redundant tool manipulation, \n" "Color change(s) for unused extruder(s) was(were) deleted")), _(L("Info"))); } + */ if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a28bb61f28..5b27c8870c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -133,7 +133,7 @@ GLCanvas3D::LayersEditing::LayersEditing() , m_slicing_parameters(nullptr) , m_layer_height_profile_modified(false) #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - , m_adaptive_cusp(0.0f) + , m_adaptive_quality(0.5f) #endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE , state(Unknown) , band_width(2.0f) @@ -268,24 +268,24 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const ImGui::Separator(); if (imgui.button(_(L("Adaptive")))) - wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_cusp)); + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_quality)); ImGui::SameLine(); float text_align = ImGui::GetCursorPosX(); ImGui::AlignTextToFramePadding(); - imgui.text(_(L("Cusp (mm)"))); + imgui.text(_(L("Quality / Speed"))); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::TextUnformatted(_(L("I am a tooltip"))); + ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed."))); ImGui::EndTooltip(); } ImGui::SameLine(); float widget_align = ImGui::GetCursorPosX(); ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f); - m_adaptive_cusp = clamp(0.0f, 0.5f * (float)m_slicing_parameters->layer_height, m_adaptive_cusp); - ImGui::SliderFloat("", &m_adaptive_cusp, 0.0f, 0.5f * (float)m_slicing_parameters->layer_height, "%.3f"); + m_adaptive_quality = clamp(0.0f, 1.f, m_adaptive_quality); + ImGui::SliderFloat("", &m_adaptive_quality, 0.0f, 1.f, "%.2f"); ImGui::Separator(); if (imgui.button(_(L("Smooth")))) @@ -645,10 +645,10 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas) } #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp) +void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor) { this->update_slicing_parameters(); - m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, cusp); + m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, quality_factor); const_cast(m_model_object)->layer_height_profile = m_layer_height_profile; m_layers_texture.valid = false; canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); @@ -712,11 +712,6 @@ void GLCanvas3D::LayersEditing::update_slicing_parameters() m_slicing_parameters = new SlicingParameters(); *m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z); } - -#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - if (m_adaptive_cusp == 0.0f) - m_adaptive_cusp = 0.25f * m_slicing_parameters->layer_height; -#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas) @@ -1016,24 +1011,25 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D std::vector& colors, std::vector& cp_legend_items) { - std::vector custom_gcode_per_height = wxGetApp().plater()->model().custom_gcode_per_height; + std::vector custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z; const int extruders_cnt = wxGetApp().extruders_edited_cnt(); if (extruders_cnt == 1) { - if (custom_gcode_per_height.empty()) { - cp_legend_items.push_back(I18N::translate_utf8(L("Default print color"))); + if (custom_gcode_per_print_z.empty()) { + cp_legend_items.emplace_back(I18N::translate_utf8(L("Default print color"))); colors = colors_in; return; } std::vector> cp_values; + cp_values.reserve(custom_gcode_per_print_z.size()); std::vector print_zs = canvas.get_current_print_zs(true); - for (auto custom_code : custom_gcode_per_height) + for (auto custom_code : custom_gcode_per_print_z) { if (custom_code.gcode != ColorChangeCode) continue; - auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.height - DoubleSlider::epsilon()); + auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - DoubleSlider::epsilon()); if (lower_b == print_zs.end()) continue; @@ -1044,14 +1040,14 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D // to avoid duplicate values, check adding values if (cp_values.empty() || !(cp_values.back().first == previous_z && cp_values.back().second == current_z)) - cp_values.push_back(std::pair(previous_z, current_z)); + cp_values.emplace_back(std::pair(previous_z, current_z)); } const auto items_cnt = (int)cp_values.size(); if (items_cnt == 0) // There is no one color change, but there is/are some pause print or custom Gcode { - cp_legend_items.push_back(I18N::translate_utf8(L("Default print color"))); - cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code"))); + cp_legend_items.emplace_back(I18N::translate_utf8(L("Default print color"))); + cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code"))); colors = colors_in; return; } @@ -1060,7 +1056,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D colors.resize(colors_in.size(), 0.0); ::memcpy((void*)(colors.data()), (const void*)(colors_in.data() + (color_cnt - 1) * 4), 4 * sizeof(float)); - cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code"))); + cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code"))); size_t color_pos = 4; for (int i = items_cnt; i >= 0; --i, color_pos+=4) @@ -1072,15 +1068,15 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D std::string id_str = std::to_string(i + 1) + ": "; if (i == 0) { - cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values[0].first).str()); + cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values[0].first).str()); break; } if (i == items_cnt) { - cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str()); + cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str()); continue; } - cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str()); + cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str()); } } else @@ -1094,20 +1090,20 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D size_t color_in_pos = 4 * (color_cnt - 1); for (unsigned int i = 0; i < (unsigned int)extruders_cnt; ++i) - cp_legend_items.push_back((boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str()); + cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str()); ::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float)); color_pos += 4; color_in_pos -= 4; - cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code"))); + cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code"))); - int cnt = custom_gcode_per_height.size(); + int cnt = custom_gcode_per_print_z.size(); for (int i = cnt-1; i >= 0; --i) - if (custom_gcode_per_height[i].gcode == ColorChangeCode) { + if (custom_gcode_per_print_z[i].gcode == ColorChangeCode) { ::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float)); color_pos += 4; color_in_pos -= 4; - cp_legend_items.push_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_height[i].extruder % custom_gcode_per_height[i].height).str()); + cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str()); } } } @@ -1688,10 +1684,10 @@ void GLCanvas3D::reset_layer_height_profile() m_dirty = true; } -void GLCanvas3D::adaptive_layer_height_profile(float cusp) +void GLCanvas3D::adaptive_layer_height_profile(float quality_factor) { wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Adaptive"))); - m_layers_editing.adaptive_layer_height_profile(*this, cusp); + m_layers_editing.adaptive_layer_height_profile(*this, quality_factor); m_layers_editing.state = LayersEditing::Completed; m_dirty = true; } @@ -1925,7 +1921,11 @@ void GLCanvas3D::render() m_camera.debug_render(); #endif // ENABLE_CAMERA_STATISTICS +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this); +#else wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG wxGetApp().imgui()->render(); @@ -2633,8 +2633,8 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) if (m_extra_frame_requested || mouse3d_controller_applied) { m_dirty = true; - evt.RequestMore(); m_extra_frame_requested = false; + evt.RequestMore(); } else m_dirty = false; @@ -5390,7 +5390,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c // For coloring by a color_print(M600), return a parsed color. bool color_by_color_print() const { return color_print_values!=nullptr; } const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const { - const Model::CustomGCode value(layers[layer_idx]->print_z + EPSILON, "", 0, ""); + const Model::CustomGCode value{layers[layer_idx]->print_z + EPSILON, "", 0, ""}; auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value); return (it - color_print_values->begin()) % number_tools(); } @@ -5401,7 +5401,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c auto it = std::find_if(color_print_values->begin(), color_print_values->end(), [print_z](const Model::CustomGCode& code) - { return fabs(code.height - print_z) < EPSILON; }); + { return fabs(code.print_z - print_z) < EPSILON; }); if (it != color_print_values->end()) { const std::string& code = it->gcode; @@ -5421,7 +5421,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c } } - const Model::CustomGCode value(print_z + EPSILON, "", 0, ""); + const Model::CustomGCode value{print_z + EPSILON, "", 0, ""}; it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value); while (it != color_print_values->begin()) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index bd31527b1d..e07ccd7fdd 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -185,7 +185,7 @@ private: bool m_layer_height_profile_modified; #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - mutable float m_adaptive_cusp; + mutable float m_adaptive_quality; mutable HeightProfileSmoothingParams m_smooth_params; #endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE @@ -236,8 +236,8 @@ private: void accept_changes(GLCanvas3D& canvas); void reset_layer_height_profile(GLCanvas3D& canvas); #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - void adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp); - void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_paramsn); + void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor); + void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params); #endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static float get_cursor_z_relative(const GLCanvas3D& canvas); @@ -541,7 +541,7 @@ public: #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void reset_layer_height_profile(); - void adaptive_layer_height_profile(float cusp); + void adaptive_layer_height_profile(float quality_factor); void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params); #endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index edb244b347..2eb316be0f 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -569,7 +569,7 @@ void Preview::update_view_type(bool slice_completed) { const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config; - const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_height.empty() /*&& + const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.empty() /*&& (wxGetApp().extruders_edited_cnt()==1 || !slice_completed) */? _(L("Color Print")) : config.option("wiping_volumes_matrix")->values.size() > 1 ? @@ -600,7 +600,7 @@ void Preview::create_double_slider() Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { Model& model = wxGetApp().plater()->model(); - model.custom_gcode_per_height = m_slider->GetTicksValues(); + model.custom_gcode_per_print_z = m_slider->GetTicksValues(); m_schedule_background_process(); update_view_type(false); @@ -646,7 +646,7 @@ void Preview::check_slider_values(std::vector& ticks_from_mo ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(), [layers_z](Model::CustomGCode val) { - auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.height - DoubleSlider::epsilon()); + auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.print_z - DoubleSlider::epsilon()); return it == layers_z.end(); }), ticks_from_model.end()); @@ -669,7 +669,7 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min(); bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max(); - std::vector &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_height; + std::vector &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z; check_slider_values(ticks_from_model, layers_z); m_slider->SetSliderValues(layers_z); @@ -789,7 +789,7 @@ void Preview::load_print_as_fff(bool keep_z_range) colors.push_back("#808080"); // gray color for pause print or custom G-code if (!gcode_preview_data_valid) - color_print_values = wxGetApp().plater()->model().custom_gcode_per_height; + color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z; } else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) ) { diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 33e526083a..90ef017fcd 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -254,6 +254,16 @@ bool ImGuiWrapper::begin(const wxString &name, int flags) return begin(into_u8(name), flags); } +bool ImGuiWrapper::begin(const std::string& name, bool* close, int flags) +{ + return ImGui::Begin(name.c_str(), close, (ImGuiWindowFlags)flags); +} + +bool ImGuiWrapper::begin(const wxString& name, bool* close, int flags) +{ + return begin(into_u8(name), close, flags); +} + void ImGuiWrapper::end() { ImGui::End(); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 7cce60367d..5118af036d 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -56,6 +56,8 @@ public: bool begin(const std::string &name, int flags = 0); bool begin(const wxString &name, int flags = 0); + bool begin(const std::string& name, bool* close, int flags = 0); + bool begin(const wxString& name, bool* close, int flags = 0); void end(); bool button(const wxString &label); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index b3d7c0e4fe..ad5be88d8c 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -5,6 +5,9 @@ #include "GUI_App.hpp" #include "PresetBundle.hpp" #include "AppConfig.hpp" +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG +#include "GLCanvas3D.hpp" +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG #include @@ -184,7 +187,10 @@ Mouse3DController::Mouse3DController() , m_device(nullptr) , m_device_str("") , m_running(false) - , m_settings_dialog(false) + , m_show_settings_dialog(false) +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + , m_settings_dialog_closed_by_user(false) +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG { m_last_time = std::chrono::high_resolution_clock::now(); } @@ -229,8 +235,11 @@ bool Mouse3DController::apply(Camera& camera) if (!m_running && is_device_connected()) { disconnect_device(); - // hides the settings dialog if the user re-plug the device - m_settings_dialog = false; + // hides the settings dialog if the user un-plug the device + m_show_settings_dialog = false; +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + m_settings_dialog_closed_by_user = false; +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG } // check if the user plugged the device @@ -240,88 +249,144 @@ bool Mouse3DController::apply(Camera& camera) return is_device_connected() ? m_state.apply(camera) : false; } +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG +void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const +#else void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG { - if (!m_running || !m_settings_dialog) + if (!m_running || !m_show_settings_dialog) return; - ImGuiWrapper& imgui = *wxGetApp().imgui(); - - imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f); - - imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); - - const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator); - ImGui::PushStyleColor(ImGuiCol_Text, color); - imgui.text(_(L("Device:"))); - ImGui::PopStyleColor(); - ImGui::SameLine(); - imgui.text(m_device_str); - - ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, color); - imgui.text(_(L("Speed:"))); - ImGui::PopStyleColor(); - - float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale; - if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f")) - m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale); - - float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale; - if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f")) - m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale); - - ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, color); - imgui.text(_(L("Deadzone:"))); - ImGui::PopStyleColor(); - - float translation_deadzone = (float)m_state.get_translation_deadzone(); - if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f")) - m_state.set_translation_deadzone((double)translation_deadzone); - - float rotation_deadzone = m_state.get_rotation_deadzone(); - if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f")) - m_state.set_rotation_deadzone(rotation_deadzone); - -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - ImGui::Separator(); - ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, color); - imgui.text("DEBUG:"); - imgui.text("Vectors:"); - ImGui::PopStyleColor(); - Vec3f translation = m_state.get_translation().cast(); - Vec3f rotation = m_state.get_rotation(); - ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); - ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); - - ImGui::PushStyleColor(ImGuiCol_Text, color); - imgui.text("Queue size:"); - ImGui::PopStyleColor(); - - int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() }; - int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() }; - int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() }; - - ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly); - ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly); - ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly); - - int queue_size = (int)m_state.get_queues_max_size(); - if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly)) +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + // when the user clicks on [X] or [Close] button we need to trigger + // an extra frame to let the dialog disappear + if (m_settings_dialog_closed_by_user) { - if (queue_size > 0) - m_state.set_queues_max_size(queue_size); + m_show_settings_dialog = false; + m_settings_dialog_closed_by_user = false; + canvas.request_extra_frame(); + return; } - ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, color); - imgui.text("Camera:"); - ImGui::PopStyleColor(); - Vec3f target = wxGetApp().plater()->get_camera().get_target().cast(); - ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); + Size cnv_size = canvas.get_canvas_size(); +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + + ImGuiWrapper& imgui = *wxGetApp().imgui(); +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + 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); +#else + imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f); +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + static ImVec2 last_win_size(0.0f, 0.0f); + bool shown = true; + if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse)) + { + if (shown) + { + ImVec2 win_size = ImGui::GetWindowSize(); + if ((last_win_size.x != win_size.x) || (last_win_size.y != win_size.y)) + { + // when the user clicks on [X] button, the next time the dialog is shown + // has a dummy size, so we trigger an extra frame to let it have the correct size + last_win_size = win_size; + canvas.request_extra_frame(); + } +#else + imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + + const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text(_(L("Device:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(m_device_str); + + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text(_(L("Speed:"))); + ImGui::PopStyleColor(); + + float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale; + if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f")) + m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale); + + float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale; + if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f")) + m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale); + + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text(_(L("Deadzone:"))); + ImGui::PopStyleColor(); + + float translation_deadzone = (float)m_state.get_translation_deadzone(); + if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f")) + m_state.set_translation_deadzone((double)translation_deadzone); + + float rotation_deadzone = m_state.get_rotation_deadzone(); + if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f")) + m_state.set_rotation_deadzone(rotation_deadzone); + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + ImGui::Separator(); + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text("DEBUG:"); + imgui.text("Vectors:"); + ImGui::PopStyleColor(); + Vec3f translation = m_state.get_translation().cast(); + Vec3f rotation = m_state.get_rotation(); + ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); + + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text("Queue size:"); + ImGui::PopStyleColor(); + + int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() }; + int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() }; + int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() }; + + ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly); + ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly); + ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly); + + int queue_size = (int)m_state.get_queues_max_size(); + if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly)) + { + if (queue_size > 0) + m_state.set_queues_max_size(queue_size); + } + + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text("Camera:"); + ImGui::PopStyleColor(); + Vec3f target = wxGetApp().plater()->get_camera().get_target().cast(); + ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + + ImGui::Separator(); + if (imgui.button(_(L("Close")))) + { + // the user clicked on the [Close] button + m_settings_dialog_closed_by_user = true; + canvas.set_as_dirty(); + } + } + else + { + // the user clicked on the [X] button + m_settings_dialog_closed_by_user = true; + canvas.set_as_dirty(); + } + } +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG imgui.end(); } diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index cc03d4a24c..543c44e775 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -18,6 +18,9 @@ namespace Slic3r { namespace GUI { struct Camera; +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG +class GLCanvas3D; +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG class Mouse3DController { @@ -130,7 +133,13 @@ class Mouse3DController hid_device* m_device; std::string m_device_str; bool m_running; - bool m_settings_dialog; +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + mutable bool m_show_settings_dialog; + // set to true when ther user closes the dialog by clicking on [X] or [Close] buttons + mutable bool m_settings_dialog_closed_by_user; +#else + bool m_show_settings_dialog; +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG std::chrono::time_point m_last_time; public: @@ -146,9 +155,13 @@ public: bool apply(Camera& camera); - bool is_settings_dialog_shown() const { return m_settings_dialog; } - void show_settings_dialog(bool show) { m_settings_dialog = show && is_running(); } + bool is_settings_dialog_shown() const { return m_show_settings_dialog; } + void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); } +#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG + void render_settings_dialog(GLCanvas3D& canvas) const; +#else void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const; +#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG private: bool connect_device(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 29b83bebab..79ebd28505 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2370,7 +2370,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ config += std::move(config_loaded); } - this->model.custom_gcode_per_height = model.custom_gcode_per_height; + this->model.custom_gcode_per_print_z = model.custom_gcode_per_print_z; } if (load_config) @@ -2789,7 +2789,7 @@ void Plater::priv::reset() // The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here this->sidebar->show_sliced_info_sizer(false); - model.custom_gcode_per_height.clear(); + model.custom_gcode_per_print_z.clear(); } void Plater::priv::mirror(Axis axis) @@ -3282,22 +3282,30 @@ void Plater::priv::reload_from_disk() input_paths.push_back(sel_filename_path); missing_input_paths.pop_back(); - std::string sel_path = fs::path(sel_filename_path).remove_filename().string(); + fs::path sel_path = fs::path(sel_filename_path).remove_filename().string(); std::vector::iterator it = missing_input_paths.begin(); while (it != missing_input_paths.end()) { // try to use the path of the selected file with all remaining missing files - std::string repathed_filename = sel_path + "/" + it->filename().string(); + fs::path repathed_filename = sel_path; + repathed_filename /= it->filename(); if (fs::exists(repathed_filename)) { - input_paths.push_back(repathed_filename); + input_paths.push_back(repathed_filename.string()); it = missing_input_paths.erase(it); } else ++it; } } + else + { + wxString message = _(L("It is not allowed to change the file to reload")) + " (" + from_u8(fs::path(search).filename().string())+ ").\n" + _(L("Do you want to retry")) + " ?"; + wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION); + if (dlg.ShowModal() != wxID_YES) + return; + } } #endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION @@ -5042,6 +5050,7 @@ void Plater::drive_ejected_callback() { if (RemovableDriveManager::get_instance().get_did_eject()) { + RemovableDriveManager::get_instance().set_did_eject(false); wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer."; wxMessageBox(message); } @@ -5260,6 +5269,7 @@ const DynamicPrintConfig* Plater::get_plater_config() const return p->config; } +// Get vector of extruder colors considering filament color, if extruder color is undefined. std::vector Plater::get_extruder_colors_from_plater_config() const { const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; @@ -5279,13 +5289,17 @@ std::vector Plater::get_extruder_colors_from_plater_config() const return extruder_colors; } +/* Get vector of colors used for rendering of a Preview scene in "Color print" mode + * It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z + */ std::vector Plater::get_colors_for_color_print() const { std::vector colors = get_extruder_colors_from_plater_config(); + colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.size()); - for (const Model::CustomGCode& code : p->model.custom_gcode_per_height) + for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z) if (code.gcode == ColorChangeCode) - colors.push_back(code.color); + colors.emplace_back(code.color); return colors; } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 9b8eaa8ec0..dbfd446b11 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -29,6 +29,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" +#include "GUI_App.hpp" // Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir. // This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions. @@ -868,6 +869,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool } // 4) Load the project config values (the per extruder wipe matrix etc). this->project_config.apply_only(config, s_project_options); + + update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config); + break; } case ptSLA: diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 6e13a59b5c..7a2464351c 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -505,6 +505,7 @@ void RemovableDriveManager::erase_callbacks() } void RemovableDriveManager::set_last_save_path(const std::string& path) { + m_last_save_path_verified = false; m_last_save_path = path; } void RemovableDriveManager::verify_last_save_path() @@ -571,4 +572,8 @@ bool RemovableDriveManager::get_did_eject() { return m_did_eject; } +void RemovableDriveManager::set_did_eject(const bool b) +{ + m_did_eject = b; +} }}//namespace Slicer::Gui diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 1b337338e9..ea4584feee 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -56,6 +56,7 @@ public: void set_is_writing(const bool b); bool get_is_writing(); bool get_did_eject(); + void set_did_eject(const bool b); std::string get_drive_name(const std::string& path); private: RemovableDriveManager(); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index c359f76624..6721e8a33e 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2538,7 +2538,7 @@ std::vector DoubleSlider::GetTicksValues() const for (const TICK_CODE& tick : m_ticks_) { if (tick.tick > val_size) break; - values.push_back(t_custom_code(m_values[tick.tick], tick.gcode, tick.extruder, tick.color)); + values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color}); } return values; @@ -2553,12 +2553,12 @@ void DoubleSlider::SetTicksValues(const std::vector& heights) m_ticks_.clear(); for (auto h : heights) { - auto it = std::lower_bound(m_values.begin(), m_values.end(), h.height - epsilon()); + auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon()); if (it == m_values.end()) continue; - m_ticks_.insert(TICK_CODE(it-m_values.begin(), h.gcode, h.extruder, h.color)); + m_ticks_.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color}); } if (!was_empty && m_ticks_.empty()) @@ -2642,7 +2642,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin return; wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp(); - if (m_ticks_.find(tick) != m_ticks_.end()) + if (m_ticks_.find(TICK_CODE{tick}) != m_ticks_.end()) icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp(); wxCoord x_draw, y_draw; @@ -3081,7 +3081,7 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus) else if (m_is_action_icon_focesed) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - const auto tick_code_it = m_ticks_.find(tick); + const auto tick_code_it = m_ticks_.find(TICK_CODE{tick}); tooltip = tick_code_it == m_ticks_.end() ? (m_state == msSingleExtruder ? _(L("For add color change use left mouse button click")) : _(L("For add change extruder use left mouse button click"))) + "\n" + @@ -3240,13 +3240,13 @@ void DoubleSlider::action_tick(const TicksAction action) const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; - const auto it = m_ticks_.find(tick); + const auto it = m_ticks_.find(TICK_CODE{tick}); if (it != m_ticks_.end()) // erase this tick { if (action == taAdd) return; - m_ticks_.erase(TICK_CODE(tick)); + m_ticks_.erase(TICK_CODE{tick}); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); @@ -3350,7 +3350,7 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z doesn't exist tick - auto it = m_ticks_.find(tick); + auto it = m_ticks_.find(TICK_CODE{ tick }); if (it == m_ticks_.end()) { // show context menu on OnRightUp() @@ -3387,7 +3387,7 @@ int DoubleSlider::get_extruder_for_tick(int tick) if (m_ticks_.empty()) return 0; - auto it = m_ticks_.lower_bound(tick); + auto it = m_ticks_.lower_bound(TICK_CODE{tick}); while (it != m_ticks_.begin()) { --it; if(it->gcode == Slic3r::ExtruderChangeCode) @@ -3454,7 +3454,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event) else if (m_show_edit_menu) { wxMenu menu; - std::set::iterator it = m_ticks_.find(m_selection == ssLower ? m_lower_value : m_higher_value); + std::set::iterator it = m_ticks_.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value }); const bool is_color_change = it->gcode == Slic3r::ColorChangeCode; append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) : @@ -3526,7 +3526,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z doesn't exist tick - auto it = m_ticks_.find(tick); + auto it = m_ticks_.find(TICK_CODE{ tick }); if (it == m_ticks_.end()) { std::string color = ""; @@ -3535,7 +3535,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); if (m_state == msSingleExtruder && !m_ticks_.empty()) { - auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), tick); + auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), TICK_CODE{ tick }); while (before_tick_it != m_ticks_.begin()) { --before_tick_it; if (before_tick_it->gcode == Slic3r::ColorChangeCode) { @@ -3580,7 +3580,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/) extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value); } - m_ticks_.insert(TICK_CODE(tick, code, extruder, color)); + m_ticks_.emplace(TICK_CODE{tick, code, extruder, color}); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); @@ -3592,7 +3592,7 @@ void DoubleSlider::edit_tick() { const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; // if on this Z exists tick - std::set::iterator it = m_ticks_.find(tick); + std::set::iterator it = m_ticks_.find(TICK_CODE{ tick }); if (it != m_ticks_.end()) { std::string edited_value; @@ -3619,7 +3619,7 @@ void DoubleSlider::edit_tick() } m_ticks_.erase(it); - m_ticks_.insert(changed_tick); + m_ticks_.emplace(changed_tick); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); } @@ -3632,9 +3632,9 @@ void DoubleSlider::change_extruder(int extruder) std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); // if on this Y doesn't exist tick - if (m_ticks_.find(tick) == m_ticks_.end()) + if (m_ticks_.find(TICK_CODE{tick}) == m_ticks_.end()) { - m_ticks_.insert(TICK_CODE(tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1])); + m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]}); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); @@ -3672,7 +3672,7 @@ void DoubleSlider::edit_extruder_sequence() while (tick <= m_max_value) { int cur_extruder = m_extruders_sequence.extruders[extruder]; - m_ticks_.insert(TICK_CODE(tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder])); + m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]}); extruder++; if (extruder == extr_cnt) @@ -3680,12 +3680,12 @@ void DoubleSlider::edit_extruder_sequence() if (m_extruders_sequence.is_mm_intervals) { value += m_extruders_sequence.interval_by_mm; - auto it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon()); + auto val_it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon()); - if (it == m_values.end()) + if (val_it == m_values.end()) break; - tick = it - m_values.begin(); + tick = val_it - m_values.begin(); } else tick += m_extruders_sequence.interval_by_layers; diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 26e334def4..ebed49efe6 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -17,6 +17,7 @@ #include #include #include "libslic3r/Model.hpp" +#include "libslic3r/GCodeWriter.hpp" namespace Slic3r { enum class ModelVolumeType : int; @@ -961,24 +962,12 @@ private: struct TICK_CODE { - TICK_CODE(int tick):tick(tick), gcode(Slic3r::ColorChangeCode), extruder(0), color("") {} - TICK_CODE(int tick, const std::string& code) : - tick(tick), gcode(code), extruder(0) {} - TICK_CODE(int tick, int extruder) : - tick(tick), gcode(Slic3r::ColorChangeCode), extruder(extruder) {} - TICK_CODE(int tick, const std::string& code, int extruder, const std::string& color) : - tick(tick), gcode(code), extruder(extruder), color(color) {} - bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; } bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; } - TICK_CODE operator=(const TICK_CODE& other) const { - TICK_CODE ret_val(other.tick, other.gcode, other.extruder, other.color); - return ret_val; - } int tick; - std::string gcode; - int extruder; + std::string gcode = Slic3r::ColorChangeCode; + int extruder = 0; std::string color; }; diff --git a/version.inc b/version.inc index 0a62ff6f35..c96a304ab3 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer") -set(SLIC3R_VERSION "2.1.0") +set(SLIC3R_VERSION "2.2.0-alpha0") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") -set(SLIC3R_RC_VERSION "2,1,0,0") -set(SLIC3R_RC_VERSION_DOTS "2.1.0.0") +set(SLIC3R_RC_VERSION "2,2,0,0") +set(SLIC3R_RC_VERSION_DOTS "2.2.0.0") From a68ede6f2df64ae97bf99ce556d4390a4c689b8d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 13:13:40 +0100 Subject: [PATCH 119/162] check_copy function --- src/libslic3r/Utils.hpp | 3 +++ src/libslic3r/utils.cpp | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index e5fae485a7..12d77c9004 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -67,6 +67,9 @@ extern std::error_code rename_file(const std::string &from, const std::string &t // Copy a file, adjust the access attributes, so that the target is writable. extern int copy_file(const std::string &from, const std::string &to); +// Compares two files, returns 0 if identical. +extern int check_copy(const std::string& origin, const std::string& copy); + // Ignore system and hidden files, which may be created by the DropBox synchronisation process. // https://github.com/prusa3d/PrusaSlicer/issues/1298 extern bool is_plain_file(const boost::filesystem::directory_entry &path); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 678ad9ed28..47a32b4ba4 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -436,8 +436,29 @@ int copy_file(const std::string &from, const std::string &to) return -1; } boost::filesystem::permissions(target, perms, ec); + return -1; + return check_copy(from, to); +} - return 0; +int check_copy(const std::string &origin, const std::string ©) +{ + std::ifstream f1(origin, std::ifstream::binary | std::ifstream::ate); + std::ifstream f2(copy, std::ifstream::binary | std::ifstream::ate); + + if (f1.fail() || f2.fail()) { + return -1; + } + + if (f1.tellg() != f2.tellg()) { + return -1; + } + + f1.seekg(0, std::ifstream::beg); + f2.seekg(0, std::ifstream::beg); + bool ident = std::equal(std::istreambuf_iterator(f1.rdbuf()), + std::istreambuf_iterator(), + std::istreambuf_iterator(f2.rdbuf())); + return(ident ? 0 : -1); } // Ignore system and hidden files, which may be created by the DropBox synchronisation process. From ef250ad539af6c63f377742525f6da7f62700ab4 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 14:09:16 +0100 Subject: [PATCH 120/162] copy check only if path is on removable device --- src/libslic3r/Utils.hpp | 2 +- src/libslic3r/utils.cpp | 5 ++--- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 12d77c9004..5ad565ae7c 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -65,7 +65,7 @@ extern std::string normalize_utf8_nfc(const char *src); extern std::error_code rename_file(const std::string &from, const std::string &to); // Copy a file, adjust the access attributes, so that the target is writable. -extern int copy_file(const std::string &from, const std::string &to); +extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false); // Compares two files, returns 0 if identical. extern int check_copy(const std::string& origin, const std::string& copy); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 47a32b4ba4..33f85a3c29 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -417,7 +417,7 @@ std::error_code rename_file(const std::string &from, const std::string &to) #endif } -int copy_file(const std::string &from, const std::string &to) +int copy_file(const std::string &from, const std::string &to, const bool with_check) { const boost::filesystem::path source(from); const boost::filesystem::path target(to); @@ -436,8 +436,7 @@ int copy_file(const std::string &from, const std::string &to) return -1; } boost::filesystem::permissions(target, perms, ec); - return -1; - return check_copy(from, to); + return (with_check ? check_copy(from, to) : 0); } int check_copy(const std::string &origin, const std::string ©) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index a8b88dd037..9d6a2a5ec7 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -34,6 +34,7 @@ #include #include "I18N.hpp" #include "GUI.hpp" +#include "RemovableDriveManager.hpp" namespace Slic3r { @@ -107,7 +108,7 @@ void BackgroundSlicingProcess::process_fff() //FIXME localize the messages // Perform the final post-processing of the export path by applying the print statistics over the file name. std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path); - if (copy_file(m_temp_output_path, export_path) != 0) + if (copy_file(m_temp_output_path, export_path, GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path)) != 0) throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?"))); m_print->set_status(95, _utf8(L("Running post-processing scripts"))); run_post_process_scripts(export_path, m_fff_print->config()); From 1361d21f7596b1f1c8870fd3bac5679508282589 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 15:40:48 +0100 Subject: [PATCH 121/162] is path on removable drive --- src/slic3r/GUI/RemovableDriveManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7a2464351c..d9cecc3e8d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -380,9 +380,11 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) { if (m_current_drives.empty()) return false; + std::size_t found = path.find_last_of("/"); + std::string new_path = path.substr(0,found); for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { - if(compare_filesystem_id(path, (*it).path)) + if(compare_filesystem_id(new_path, (*it).path)) return true; } return false; From 3d08e8ae321a5c75976b336055a9bc0208c47507 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 18 Dec 2019 15:40:48 +0100 Subject: [PATCH 122/162] is path on removable drive --- src/slic3r/GUI/RemovableDriveManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7a2464351c..d9cecc3e8d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -380,9 +380,11 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) { if (m_current_drives.empty()) return false; + std::size_t found = path.find_last_of("/"); + std::string new_path = path.substr(0,found); for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { - if(compare_filesystem_id(path, (*it).path)) + if(compare_filesystem_id(new_path, (*it).path)) return true; } return false; From 7b95ec486f7ab2c6bff18fada8f8e0f08bfa9d58 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Dec 2019 11:47:02 +0100 Subject: [PATCH 123/162] ommit last filename when checking if path is on drive --- src/slic3r/GUI/RemovableDriveManager.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index d9cecc3e8d..7369847551 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -116,7 +116,9 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) { if (m_current_drives.empty()) return false; - int letter = PathGetDriveNumberA(path.c_str()); + std::size_t found = path.find_last_of("\\"); + std::string new_path = path.substr(0, found); + int letter = PathGetDriveNumberA(new_path.c_str()); for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { char drive = (*it).path[0]; @@ -127,7 +129,9 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } std::string RemovableDriveManager::get_drive_from_path(const std::string& path) { - int letter = PathGetDriveNumberA(path.c_str()); + std::size_t found = path.find_last_of("\\"); + std::string new_path = path.substr(0, found); + int letter = PathGetDriveNumberA(new_path.c_str()); for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { char drive = (*it).path[0]; @@ -391,10 +395,12 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) } std::string RemovableDriveManager::get_drive_from_path(const std::string& path) { + std::size_t found = path.find_last_of("/"); + std::string new_path = path.substr(0, found); //check if same filesystem for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { - if (compare_filesystem_id(path, (*it).path)) + if (compare_filesystem_id(new_path, (*it).path)) return (*it).path; } return ""; From d7698a36cbf0752a00fc5bd9789ffc2668e5e6d0 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Dec 2019 14:19:41 +0100 Subject: [PATCH 124/162] changes in plater.cpp --- src/slic3r/GUI/Plater.cpp | 26 +++++++++++------------- src/slic3r/GUI/RemovableDriveManager.cpp | 19 +++++++++-------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 174d6b1897..26647a729b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3611,17 +3611,14 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) } else if (wxGetApp().get_mode() == comSimple) show_action_buttons(false); - if(RemovableDriveManager::get_instance().get_is_writing()) - { - RemovableDriveManager::get_instance().set_is_writing(false); - RemovableDriveManager::get_instance().verify_last_save_path(); - if (!RemovableDriveManager::get_instance().is_last_drive_removed()) - { - RemovableDriveManager::get_instance().erase_callbacks(); - RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, q)); + if(!canceled && RemovableDriveManager::get_instance().get_is_writing()) + { + //if (!RemovableDriveManager::get_instance().is_last_drive_removed()) + //{ + RemovableDriveManager::get_instance().set_is_writing(false); show_action_buttons(false); - } + //} } } @@ -4755,19 +4752,20 @@ void Plater::export_gcode() if (! output_path.empty()) { std::string path = output_path.string(); - RemovableDriveManager::get_instance().set_is_writing(true); - RemovableDriveManager::get_instance().update(0, true); p->export_gcode(std::move(output_path), PrintHostJob()); + + RemovableDriveManager::get_instance().update(0, false); RemovableDriveManager::get_instance().set_last_save_path(path); - /* + RemovableDriveManager::get_instance().verify_last_save_path(); + if(!RemovableDriveManager::get_instance().is_last_drive_removed()) { + RemovableDriveManager::get_instance().set_is_writing(true); RemovableDriveManager::get_instance().erase_callbacks(); RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this)); } - */ + } - } void Plater::export_stl(bool extended, bool selection_only) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7369847551..603994770b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -449,7 +449,11 @@ bool RemovableDriveManager::update(const long time,const bool check) } } search_for_drives(); - if(check)check_and_notify(); + if (m_drives_count != m_current_drives.size()) + { + if (check)check_and_notify(); + m_drives_count = m_current_drives.size(); + } return !m_current_drives.empty(); } @@ -491,16 +495,12 @@ std::vector RemovableDriveManager::get_all_drives() } void RemovableDriveManager::check_and_notify() { - if(m_drives_count != m_current_drives.size()) + if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path_verified && !is_drive_mounted(m_last_save_path)) { - if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path_verified && !is_drive_mounted(m_last_save_path)) + for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { - for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) - { - (*it)(); - } + (*it)(); } - m_drives_count = m_current_drives.size(); } } void RemovableDriveManager::add_callback(std::function callback) @@ -524,6 +524,9 @@ void RemovableDriveManager::verify_last_save_path() m_last_save_path_verified = true; m_last_save_path = last_drive; m_last_save_name = get_drive_name(last_drive); + }else + { + reset_last_save_path(); } } std::string RemovableDriveManager::get_drive_name(const std::string& path) From 31b134bfccbbb1378fd65b1d86f6ec3fbcda4267 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Dec 2019 15:36:00 +0100 Subject: [PATCH 125/162] copy file into .tmp and then rename if correct --- src/libslic3r/Utils.hpp | 1 + src/libslic3r/utils.cpp | 51 ++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 5ad565ae7c..c60cf6d8c9 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -65,6 +65,7 @@ extern std::string normalize_utf8_nfc(const char *src); extern std::error_code rename_file(const std::string &from, const std::string &to); // Copy a file, adjust the access attributes, so that the target is writable. +int copy_file_inner(const std::string &from, const std::string &to); extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false); // Compares two files, returns 0 if identical. diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 33f85a3c29..e780220534 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -417,26 +417,41 @@ std::error_code rename_file(const std::string &from, const std::string &to) #endif } +int copy_file_inner(const std::string& from, const std::string& to) +{ + const boost::filesystem::path source(from); + const boost::filesystem::path target(to); + static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644 + + // Make sure the file has correct permission both before and after we copy over it. + // NOTE: error_code variants are used here to supress expception throwing. + // Error code of permission() calls is ignored on purpose - if they fail, + // the copy_file() function will fail appropriately and we don't want the permission() + // calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.) + // or when the target file doesn't exist. + boost::system::error_code ec; + boost::filesystem::permissions(target, perms, ec); + boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec); + if (ec) { + return -1; + } + boost::filesystem::permissions(target, perms, ec); + return 0; +} + int copy_file(const std::string &from, const std::string &to, const bool with_check) { - const boost::filesystem::path source(from); - const boost::filesystem::path target(to); - static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644 - - // Make sure the file has correct permission both before and after we copy over it. - // NOTE: error_code variants are used here to supress expception throwing. - // Error code of permission() calls is ignored on purpose - if they fail, - // the copy_file() function will fail appropriately and we don't want the permission() - // calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.) - // or when the target file doesn't exist. - boost::system::error_code ec; - boost::filesystem::permissions(target, perms, ec); - boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec); - if (ec) { - return -1; - } - boost::filesystem::permissions(target, perms, ec); - return (with_check ? check_copy(from, to) : 0); + std::string to_temp = to + ".tmp"; + int ret_val = copy_file_inner(from,to_temp); + if(ret_val == 0 && with_check) + { + ret_val = check_copy(from, to_temp); + if (ret_val == 0) + { + rename_file(to_temp, to); + } + } + return ret_val; } int check_copy(const std::string &origin, const std::string ©) From 8d52663871173ac8c4ec80ef538861eed4dfc8b5 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Dec 2019 16:27:48 +0100 Subject: [PATCH 126/162] free space check linux + mac --- src/slic3r/GUI/RemovableDriveManager.cpp | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7369847551..4279fe62cc 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -20,6 +20,7 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, #include #include #include +#include #endif namespace Slic3r { @@ -309,20 +310,27 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str //if not same file system - could be removable drive if(!compare_filesystem_id(path, parent_path)) { - //user id - struct stat buf; - stat(path.c_str(), &buf); - uid_t uid = buf.st_uid; - std::string username(std::getenv("USER")); - struct passwd *pw = getpwuid(uid); - if(pw != 0) + //free space + std::filesystem::space_info fs_si = std::filesystem::space(path); + //std::cout << "Free space: " << fs_si.free << "Available space: " << fs_si.available << " " << path << '\n'; + if(fs_si.free != 0 && fs_si.available != 0) { - if(pw->pw_name == username) + //user id + struct stat buf; + stat(path.c_str(), &buf); + uid_t uid = buf.st_uid; + std::string username(std::getenv("USER")); + struct passwd *pw = getpwuid(uid); + if(pw != 0) { - std::string name = basename(const_cast(path.c_str())); - m_current_drives.push_back(DriveData(name,path)); + if(pw->pw_name == username) + { + std::string name = basename(const_cast(path.c_str())); + m_current_drives.push_back(DriveData(name,path)); + } } } + } } bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, const std::string &path_b) From 74e24213e6f960d61d2df1694b24adb5d4a33dab Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Dec 2019 17:05:23 +0100 Subject: [PATCH 127/162] boost::filesystem instead std:: --- src/slic3r/GUI/RemovableDriveManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 23ab4bb7f6..353337e473 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -20,7 +20,7 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, #include #include #include -#include +#include #endif namespace Slic3r { @@ -311,9 +311,9 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str if(!compare_filesystem_id(path, parent_path)) { //free space - std::filesystem::space_info fs_si = std::filesystem::space(path); + boost::filesystem::space_info si = boost::filesystem::space(path); //std::cout << "Free space: " << fs_si.free << "Available space: " << fs_si.available << " " << path << '\n'; - if(fs_si.free != 0 && fs_si.available != 0) + if(si.available != 0) { //user id struct stat buf; From e9bb3c24509381cd805ad43e6b8ff5e92e342692 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 20 Dec 2019 12:11:58 +0100 Subject: [PATCH 128/162] 3mf and amf import: keep loaded volumes transformation as a member of ModelVolume without applying it to the mesh --- src/libslic3r/Format/3mf.cpp | 16 ++++++++++++++++ src/libslic3r/Format/AMF.cpp | 24 ++++++++++++++++++++---- src/libslic3r/Model.hpp | 5 +++++ src/libslic3r/Technologies.hpp | 3 +++ src/slic3r/GUI/Plater.cpp | 4 ++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 88e1a9047f..376b34ca8a 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1713,7 +1713,9 @@ namespace Slic3r { break; } } +#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE Transform3d inv_matrix = volume_matrix_to_object.inverse(); +#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE // splits volume out of imported geometry TriangleMesh triangle_mesh; @@ -1733,11 +1735,15 @@ namespace Slic3r { for (unsigned int v = 0; v < 3; ++v) { unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3; +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); +#else Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); facet.vertex[v] = has_transform ? // revert the vertices to the original mesh reference system (inv_matrix * vertex.cast()).cast() : vertex; +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE } } @@ -1745,9 +1751,15 @@ namespace Slic3r { triangle_mesh.repair(); ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + // stores the volume matrix taken from the metadata, if present + if (has_transform) + volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object); +#else // apply the volume matrix taken from the metadata, if present if (has_transform) volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object)); +#endif //ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE volume->calculate_convex_hull(); // apply the remaining volume's metadata @@ -2521,7 +2533,11 @@ namespace Slic3r { // stores volume's local matrix stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\""; +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix(); +#else const Transform3d& matrix = volume->get_matrix(); +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 4b19b8060a..847ac6f5c3 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -585,24 +585,36 @@ void AMFParserContext::endElement(const char * /* name */) stl_allocate(&stl); bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10); +#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE Transform3d inv_matrix = m_volume_transform.inverse(); +#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE for (size_t i = 0; i < m_volume_facets.size();) { stl_facet &facet = stl.facet_start[i/3]; for (unsigned int v = 0; v < 3; ++v) { unsigned int tri_id = m_volume_facets[i++] * 3; +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); +#else Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); facet.vertex[v] = has_transform ? // revert the vertices to the original mesh reference system (inv_matrix * vertex.cast()).cast() : vertex; +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE } } stl_get_size(&stl); mesh.repair(); m_volume->set_mesh(std::move(mesh)); - if (has_transform) - m_volume->set_transformation(m_volume_transform); +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + // stores the volume matrix taken from the metadata, if present + if (has_transform) + m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform); +#else + if (has_transform) + m_volume->set_transformation(m_volume_transform); +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART)) { m_volume->source.object_idx = (int)m_model.objects.size() - 1; @@ -1147,8 +1159,12 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; stream << " "; +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + const Transform3d& matrix = volume->get_matrix() * volume->source.transform.get_matrix(); +#else const Transform3d& matrix = volume->get_matrix(); - stream << std::setprecision(std::numeric_limits::max_digits10); +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + stream << std::setprecision(std::numeric_limits::max_digits10); for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) @@ -1248,7 +1264,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) pt::write_xml(oss, tree); out = oss.str(); - int del_header_pos = out.find(" void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset, transform); } +#else template void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); } +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE }; Source source; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index d503f0c64a..3d1234cbfc 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -56,4 +56,7 @@ // Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons #define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1) +// Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member +#define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1) + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8b452e9afb..ef3dae8d69 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3322,7 +3322,11 @@ void Plater::priv::reload_from_disk() new_volume->config.apply(old_volume->config); new_volume->set_type(old_volume->type()); new_volume->set_material_id(old_volume->material_id()); +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + new_volume->set_transformation(old_volume->get_transformation() * old_volume->source.transform); +#else new_volume->set_transformation(old_volume->get_transformation()); +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); new_volume->source.input_file = path; std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back()); From ba5815c6062c7a1779b949c8212c549146574a52 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 20 Dec 2019 16:02:56 +0100 Subject: [PATCH 129/162] Fixed wrong z value after reload from disk for objects with x and y rotation --- src/slic3r/GUI/Plater.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ef3dae8d69..aeb5417305 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3331,12 +3331,17 @@ void Plater::priv::reload_from_disk() new_volume->source.input_file = path; std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back()); old_model_object->delete_volume(old_model_object->volumes.size() - 1); +#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE + old_model_object->ensure_on_bed(); +#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE } } } } +#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE model.adjust_min_z(); +#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE // update 3D scene update(); From a0d47bf1674849464e77b0dbff291d176632e19d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 20 Dec 2019 17:29:23 +0100 Subject: [PATCH 130/162] Fixed a file handle leak. --- src/slic3r/GUI/wxExtensions.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 7c63e96c61..ad74e0ea0f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -433,17 +433,15 @@ static std::string icon_name_respected_to_mode(const std::string& bmp_name_in) #else const std::string folder = "white/"; #endif - std::string bmp_name = Slic3r::GUI::wxGetApp().dark_mode() ? folder + bmp_name_in : bmp_name_in; - boost::replace_last(bmp_name, ".png", ""); - FILE* fp = NULL; - fp = boost::nowide::fopen(Slic3r::var(bmp_name + ".svg").c_str(), "rb"); - if (!fp) - { - bmp_name = bmp_name_in; - boost::replace_last(bmp_name, ".png", ""); - if (fp) fclose(fp); - } - + std::string bmp_name; + if (Slic3r::GUI::wxGetApp().dark_mode()) { + bmp_name = folder + bmp_name_in; + boost::replace_last(bmp_name, ".png", ""); + } + if (bmp_name.empty()) { + bmp_name = bmp_name_in; + boost::replace_last(bmp_name, ".png", ""); + } return bmp_name; } From 8c7fa7f69edb5edaa6c1d897af54266ae4c3111e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 20 Dec 2019 17:30:38 +0100 Subject: [PATCH 131/162] Bumped up version number. --- version.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.inc b/version.inc index c96a304ab3..4add49271e 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer") -set(SLIC3R_VERSION "2.2.0-alpha0") +set(SLIC3R_VERSION "2.2.0-alpha1") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_RC_VERSION "2,2,0,0") set(SLIC3R_RC_VERSION_DOTS "2.2.0.0") From 13f1bb2e4317b1a9329f9f3b82517ff845d0b4fa Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Sat, 21 Dec 2019 12:31:32 +0100 Subject: [PATCH 132/162] An attempt to fix missing renaming from .gcode.tmp to .gcode Added a missing include --- src/libslic3r/utils.cpp | 10 +++++----- src/slic3r/GUI/RemovableDriveManager.hpp | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index e780220534..2b867c8af3 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -443,13 +443,13 @@ int copy_file(const std::string &from, const std::string &to, const bool with_ch { std::string to_temp = to + ".tmp"; int ret_val = copy_file_inner(from,to_temp); - if(ret_val == 0 && with_check) + if(ret_val == 0) { - ret_val = check_copy(from, to_temp); - if (ret_val == 0) - { + if (with_check) + ret_val = check_copy(from, to_temp); + + if (ret_val == 0) rename_file(to_temp, to); - } } return ret_val; } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index ea4584feee..1767490d10 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Slic3r { namespace GUI { From 37c64b1a62c4f734f083e16995e2adead77df895 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Sat, 21 Dec 2019 14:43:22 +0100 Subject: [PATCH 133/162] Hopefully a fix for #3342 - dark mode icons lookup --- src/slic3r/GUI/wxExtensions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index ad74e0ea0f..7b36207f52 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -437,6 +438,8 @@ static std::string icon_name_respected_to_mode(const std::string& bmp_name_in) if (Slic3r::GUI::wxGetApp().dark_mode()) { bmp_name = folder + bmp_name_in; boost::replace_last(bmp_name, ".png", ""); + if (! boost::filesystem::exists(Slic3r::var(bmp_name + ".svg"))) + bmp_name.clear(); } if (bmp_name.empty()) { bmp_name = bmp_name_in; From 0808c8fa3cbd37ecf34fcb288a1d0142f7d40616 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 11:11:48 +0100 Subject: [PATCH 134/162] Refactoring and documentation of check_copy() and copy_file() --- src/libslic3r/Utils.hpp | 5 ++++- src/libslic3r/utils.cpp | 42 +++++++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index bf0fbfa725..06c4358099 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -66,9 +66,12 @@ extern std::error_code rename_file(const std::string &from, const std::string &t // Copy a file, adjust the access attributes, so that the target is writable. int copy_file_inner(const std::string &from, const std::string &to); +// Copy file to a temp file first, then rename it to the final file name. +// If with_check is true, then the content of the copied file is compared to the content +// of the source file before renaming. extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false); -// Compares two files, returns 0 if identical. +// Compares two files, returns 0 if identical, -1 if different. extern int check_copy(const std::string& origin, const std::string& copy); // Ignore system and hidden files, which may be created by the DropBox synchronisation process. diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 2b867c8af3..b7155ddc84 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -448,31 +448,45 @@ int copy_file(const std::string &from, const std::string &to, const bool with_ch if (with_check) ret_val = check_copy(from, to_temp); - if (ret_val == 0) - rename_file(to_temp, to); + if (ret_val == 0 && rename_file(to_temp, to)) + ret_val = -1; } return ret_val; } int check_copy(const std::string &origin, const std::string ©) { - std::ifstream f1(origin, std::ifstream::binary | std::ifstream::ate); - std::ifstream f2(copy, std::ifstream::binary | std::ifstream::ate); + std::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); + std::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); - if (f1.fail() || f2.fail()) { - return -1; - } + if (f1.fail() || f2.fail()) + return -1; - if (f1.tellg() != f2.tellg()) { - return -1; - } + std::streampos fsize = f1.tellg(); + if (fsize != f2.tellg()) + return -1; f1.seekg(0, std::ifstream::beg); f2.seekg(0, std::ifstream::beg); - bool ident = std::equal(std::istreambuf_iterator(f1.rdbuf()), - std::istreambuf_iterator(), - std::istreambuf_iterator(f2.rdbuf())); - return(ident ? 0 : -1); + + // Compare by reading 8 MiB buffers one at a time. + size_t buffer_size = 8 * 1024 * 1024; + std::vector buffer_origin(buffer_size, 0); + std::vector buffer_copy(buffer_size, 0); + do { + f1.read(buffer_origin.data(), buffer_size); + f2.read(buffer_copy.data(), buffer_size); + std::streampos origin_cnt = f1.gcount(); + std::streampos copy_cnt = f2.gcount(); + if (origin_cnt != copy_cnt || + (origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0)) + // Files are different. + return -1; + fsize -= origin_cnt; + } while (f1.good() && f2.good()); + + // All data has been read and compared equal. + return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -1; } // Ignore system and hidden files, which may be created by the DropBox synchronisation process. From 9128ba766bf09f07c17597024100e3d6cfea8b5d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 11:12:15 +0100 Subject: [PATCH 135/162] Bumped up the PrusaSlicer.ini version number, so that our in house customers will get an update. --- resources/profiles/PrusaResearch.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 74bc529aee..746aaf9668 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 1.1.0 +config_version = 1.1.1-alpha2 # Where to get the updates from? config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1% From 692ed2609154ed359abdf7a6fb233e561d5f0240 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 11:54:23 +0100 Subject: [PATCH 136/162] Fix of #3366 Fixed crash due to incorrect localization of the percent sign in "The %1% infill pattern is not supposed to work at 100%% density." This happens for ES, FR, IT, UK and ZH_TW localizations. Also added a new CMake target "gettext_po_to_mo" to convert all po files to mo files, and renamed the "pot" target to "gettext_make_pot". --- CMakeLists.txt | 16 +++++++++++++++- resources/localization/es/PrusaSlicer.mo | Bin 234220 -> 234140 bytes resources/localization/es/PrusaSlicer_es.po | 2 +- resources/localization/fr/PrusaSlicer.mo | Bin 240575 -> 240576 bytes resources/localization/fr/PrusaSlicer_fr.po | 2 +- resources/localization/it/PrusaSlicer.mo | Bin 230789 -> 230709 bytes resources/localization/it/PrusaSlicer_it.po | 2 +- resources/localization/uk/PrusaSlicer.mo | Bin 128536 -> 128537 bytes resources/localization/uk/PrusaSlicer_uk.po | 2 +- resources/localization/zh_tw/PrusaSlicer.mo | Bin 167772 -> 167773 bytes .../localization/zh_tw/PrusaSlicer_zh_TW.po | 2 +- 11 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be07b5216d..2bca5a71aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,13 +394,27 @@ target_include_directories(cereal INTERFACE include) # l10n set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization") -add_custom_target(pot +add_custom_target(gettext_make_pot COMMAND xgettext --keyword=L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --debug -f "${L10N_DIR}/list.txt" -o "${L10N_DIR}/PrusaSlicer.pot" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generate pot file from strings in the source tree" ) +add_custom_target(gettext_po_to_mo + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generate localization po files (binary) from mo files (texts)" +) +file(GLOB L10N_PO_FILES "${L10N_DIR}/*/PrusaSlicer*.po") +foreach(po_file ${L10N_PO_FILES}) + GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY) + SET(mo_file "${po_dir}/PrusaSlicer.mo") + add_custom_command( + TARGET gettext_po_to_mo PRE_BUILD + COMMAND msgfmt ARGS -o ${mo_file} ${po_file} + DEPENDS ${po_file} + ) +endforeach() find_package(NLopt 1.4 REQUIRED) diff --git a/resources/localization/es/PrusaSlicer.mo b/resources/localization/es/PrusaSlicer.mo index 17ba9216d85538794e37c5a73ea07407e3b09e57..3f02722948ab6c00c0a103c2d5e412e1990793cd 100644 GIT binary patch delta 15820 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 diff --git a/resources/localization/es/PrusaSlicer_es.po b/resources/localization/es/PrusaSlicer_es.po index ef2db8b67e..088ff479bd 100644 --- a/resources/localization/es/PrusaSlicer_es.po +++ b/resources/localization/es/PrusaSlicer_es.po @@ -6865,7 +6865,7 @@ msgstr "Textura" #: src/slic3r/GUI/ConfigManipulation.cpp:200 msgid "The %1% infill pattern is not supposed to work at 100%% density." -msgstr "Se supone que el patrón de relleno %1% no funciona a una densidad del 100%." +msgstr "Se supone que el patrón de relleno %1% no funciona a una densidad del 100%%." #: src/slic3r/GUI/FirmwareDialog.cpp:530 #, possible-c-format diff --git a/resources/localization/fr/PrusaSlicer.mo b/resources/localization/fr/PrusaSlicer.mo index 130bda3343d5705be942822470f72e269cfe9b89..f43e20ddbf69c826b3f6b128991b514cab852643 100644 GIT binary patch delta 3356 zcmXZeeN@)v9mnynd>xtjkV?#FZqgJGQ+cRBU7F@&V2Tfr4r98^HUrG5fOU%~=*gy8 zftpRJ6rng+o5$J1Y@Vs*YIAc*C(k@Pm2+oFCr{3`)oSlg*ZtS)`hI`E`+B~v-+ipT z$6M_^4ozMWoo{9rZgxw>>>+MjaWS69%c$pX4|OZXq+8q`#K*8(C$meKj8})bMad_o zxK(34)?nXMw=K8_m*cQBw})^$9>TBEJo?>(mq)l=M@5P0Zqs=%c%<7u@Im|#XW#0U zjp?I81wX<&iQmIE>^|D90pG+toHxd;3}3(uOvrG19jD?f^h~!DEXa(yRZv(*Vh~=# z!(iMOc&V)`)+_T#Vl4HWgpPQjEJjxDxLm{s;?kz#VQ2a23wMcX1>p<+v@x zyeNfJ6q<1cmgl;S#y9X5?7#^285e~WFXB`Y82b`ySs{o@$Gc(*KObkv=0 zpO9ZV!7YLO^oed8$rn#@J4inI@npA2B(~n|wuZ!+DQ-Xco*I<&+U24$D8pAYHAbayM2r+P%|)lf!hJRfUUTx(5)*CW)`^>5dYvl z21vXEj}v!YxZ8$G3#7Ocz)#8*-G!5^_R4qM~a9Y>%V%t4)^Le%@KaWg)J+MEN| zhI|HUAhXtT{%@dANTM4q#p|&g_hS|I#^j1H(k$#jJQjyC(iy1xp|q0SjWepkd0&j` z_zu+XcgNyZ)E+vFeer`T&i^n9S4e0E`mPHjNsT!T$BL12 z{;1nF%tj691dhi)V7Zu!`RTH0%;KfN|=x=hqskB?c3 z?Zl1vC05k&@nF-f+)Rade2d$=X^3Sdi(=MhfN8yXbZFoV<`Q2-?TyGYZt0kdui!G&^M3VVDd%Dt zaUtG|@8CG>-{3X@7ocWrX9MSdAX8PaGki?Sc7?Ti6PM`+yTeCm1I{7-FX}GOdp68e zBkGiVfmt|iPngMae3bY})Sl}3oLdzRK-JrTT8eL<-?{# zFp>vVn95#g#x=xeU*sYop1D7)Vda5vQ`Vw3;WIcK+fWs^qej+&qwyQm#WbqPjjyiF zN6mCm%n}@|^S}JN0{>)CFE+(&LEVh4s2{$A^w|D{nyGWB3+ivN{H2(eWBDtnnf(&= z`%VW#d_C&Q?~U;~|H%}zOH)uI%R)7jkE);m)zBi;QY=Ajsx_z^ZVT$Y`j~rBOK}j@ z@LQ<8^LEVhs3rOg_5Z`VHHQ~^pf*b~>W5=cyFLfiU_NU1-jAB%3QWNk)YP9vRs0F6 zqj4?a%1%U`vK$x(;=UcA=K|DC(Q@#!EG6m33*AosOhc#&u~vGG>VXeDnVSZ1@nG delta 3363 zcmXZfe^l4i9mnxEyw%K%Qer9@;BS5;$qx&E9WzbR2`Q+MrfD|Kjv?wygy|PVk(NuX z5Xq%vijZcxSy{H4JEqy(+&n2~Zf$4f+K$r6GgoW1+MciO_pir&zrUaF{oH%s_ueo3 zvOVsd_PAFjJQ|r{W`FMQmWH_l+&1A{{3Bk*nRs%b+gwZ<1UKU=_*J?`zWZQ*hTAoClyIxtBtE!hsM|kq5njNl znQp@|l)B8ehil!`vG2EiAz4S#IUH8?!M!+wCY$#CtI|$1N3$aw2Z4X;hK8 z1wY4EF+SJr2%f_GaNTgX=kZTC64&1DmXB}XQjEDHxD4}%|B9uUnCDi4E3gQEjYBbM zgxhSK5}|RDMk`Ln@{w-C@F)(#4otzGqr!`GP%|&XV|Wl%vhvYx3HS{r#xj91Zn>;z z=2*9jz**#X6}X+iuL{G=k4<$u$LD>fF+lR4VHqeV zj(r!n&BvmL!jc~Tf!ipao3qeu1~%bGvCJH6@a$rqCqI3O+qei{e2vC&5??;*_IKi6 zl(~ICytkZFftAa`%+_I7;u8ja=#C5US}e!CScyF`Wp$Wo4#p9W#DUCo66$^^t7LcMq^fY< z=b{F_74`k5XnX**hYn+JY_H<{52kU2gjS%}kHSn+qvm54`GuH_+p!NGL6zVvs@9iK zD=~PD+h)u~P3Sm|!QW#J-mo@o>hY-e)kSD%MvbU*--0(|JE~S!aR82Hpwn<3_Q0QE zDjvra{1h88uG*~-TTrF_9JTbFYoaAU%{&V=fyiVUdf|hpQmjSI@W-eD?ZGlUhr@Bg zI=2y6iHUd^wSs3*SM3*=iD|WAfTgIFsX@(nGpaPr$V4L6O2bLKi5kG$sE*%9?e4$f zZPmksl8>-LiT*#AA=UohG03gxi~V84Jj_Y+``;ub;S8laJl(whL=fGas-e z3@ihSdB5e+(B|5Ns__B*9)63nF=1<{`7%_^YB3FWpl1GV^z#d-33QLyfa4x&!OyQq?Ujau6HUE#TG)Nap5^;e2Iu8*LO-_v*p9*EG;NG_sk))Do_ z=Fnj-YHt*yZn6~^k9DY<^4Vy-2UW@=sDXTlItBkl-2*+J4+H6s8dxr>gps>xbfvKz z)nOI(!wsm8_Mu*Q0#on;>Tdr!8u#Aqc02J1)Jl}2j$wT?Zowwvw^0KseIXp{GVG-D zzmmpKKB&Yr_ChPJB0jr^i-dUc-cZBUE#aozfZBx5;1E2B>i9frW*s;Tzd>D0nfu)M z)wLO@l`f4s50iBMAO5bvUoxl%TcWn1ZpH(sFTRJ2*nWpvsdK0c>Mzm!Cs8j)^H)$S z`)}0utu@45QCEHs?4t9ZLPNWB2x?|Is23HWIw(TDXf~=8527~JW2hUh9`#&9)SakO z>_ffy9n{`A8TA6HM4zJm{;=!X!UNZ%HcJZXi^EX6J`eT60@Ut(0JX#wn2K$vr9X@6 z_+!*SV_pnbb^_{@iz|sEbjXwF-5LwxddX1ofM9bboDn<;L{NnAg)QW4pG+WH$1zPvYx^1AKY? F{{b5o5n%uT diff --git a/resources/localization/fr/PrusaSlicer_fr.po b/resources/localization/fr/PrusaSlicer_fr.po index cc796ba743..243fb44e9e 100644 --- a/resources/localization/fr/PrusaSlicer_fr.po +++ b/resources/localization/fr/PrusaSlicer_fr.po @@ -7013,7 +7013,7 @@ msgstr "Texture" #: src/slic3r/GUI/ConfigManipulation.cpp:200 msgid "The %1% infill pattern is not supposed to work at 100%% density." -msgstr "Le modèle de remplissage %1% n'est pas censé fonctionner avec une densité de 100%." +msgstr "Le modèle de remplissage %1% n'est pas censé fonctionner avec une densité de 100%%." #: src/slic3r/GUI/FirmwareDialog.cpp:530 #, c-format diff --git a/resources/localization/it/PrusaSlicer.mo b/resources/localization/it/PrusaSlicer.mo index 2f17472a6c72eefd2fecb3af69276c2f01b487b8..be6f9fd448d56957ce9b7a42f506dfa68fb4bf39 100644 GIT binary patch delta 15820 zcmXZicVJG}AII^V=h`z;v5F*C%!m+T#-6qJ-g`7QF|J*serD}iTdkrsO3kXYrIaXD zMQCk`TB-7Tf1Y#xdYyCbz2~0uJ>PTgV@#cu>8qKUc9p5@9dI1yj~4+>XI%0!z{!rU zF#rQ!1vr^72-9I0?!n?%7jIw;7I_`uWW{bc0!LyNe2n?fc@yAdfc%&qBQZBtdK2I| zVHDcZkQc{bT3m)7;(9!bNAVHPNe*y6z;XWuIL&;HGY?h2{a=8S8DC=_O!F?lNri<_ z11o`=Ky^%m4N((q_09`$Qc@U1gI+ug_277W<5X0~|3l4S6)GZMU}`*wy8k$8W(lbN z67BV?7)bpVs-J&sJ;i%7kYJC3I>?I}KtWW;B{3tGL%q0`tv5r>pbKgseeLy8s25E| z7Z;(PUuN4kV-D&EtiRan-UA93x$wq%*6}%wsjmz0IeqatR>qD#pTC3U7)*UH2H_8= z0bN6_^mp2Fwk$3|Eb zhoGKYiAttzSPT)Y(I3P0{_IagMe+u!A72Ka<0)G+P|(bR zFam3#LOTqVe3PwnZTm{pw%dl4@F)(z|4`5O%jk2O;8N6p?xXJaWikWJhPtmvCZFd_ zpwNZ}?f)yNC3uZ`AZ=!!e>dbo9Vi8HIF>{0=k2H$>_Lf z5o$oa(Z|w^!hO`ocpsP-l+Nn&9~_NPBWr<$unTHHpIFzU26PN{-|wi%+{M|Lj7q}k z!Da#*QRm4~)B$uFHQ>uw61^uBG_sIvCRCBAq@hCn)?T%g9eNGDP|5FsSMn9rD{0+6wZ=%*VWeyYiJgAuzMZG8r zHPBl2dSg`1bihcAL!BdQF%Ex5O{i*4bAB|zRNDVzC}>+uLS^%M)QfJSB6H80jCw)( zTqd+3Sc-ai)P4O?10RcJa1CmS5>Ye0iCVf>SP+9g^f~pl|6?db<76z42e2GIN3DIa z+-7^$Ma^goYUW!|9qqxYc*UA4k4fhCs27eweFYbxBK(DQH+o8z0~D0izoJ6xZn1E^U1!^YmP}%!IsEJ4otVew?7Q$~(2U-#q!Qe2{e=M${-U?6Pt1!M#iTNWc66aAl@xF)LP$09o_$-mNIuy z^P=*oT~QU)-W0WjgHZ1oiS+L|Gbt!Zmf8y&Y<)j!Tb{&M_!oxaAH_`Q-{U&!d5W8J z;uz{hS5Qmy5?5o^5++CXV$J|^0(GvujnFn{|79&{W||wd6veP0mPf5wXVk$FZ=H#n z!7|j^Z%0Mo7%H?kP)Yh06|pRlrr&T>#G&3Fbz6# zC!s<;6SbDhP?6Y&vG@~eCK<|_j>1t9DUWlpF=`+;Yetwh(#q;W7Ih?2-V>{+rAVhQ{RtO$m&X!%tXdiHuvqs zFs|>zXuN_tH!@c-+qWJT<~c8(!fr0Ci#0E5Rn>gGMx%Da4h+FVs5SrHwx_6Of9aqm z5RHn+Q0$DetPfBJScB>&I=i=RBiOfRWUwVFuEtra3@9tYx-YKGch&u`qVD zPQzo=cVZL{u5AXe9u=uWs9ZUT+6~w3_51d^ua3`Yp#7hYg4VDVeuQ0cC2mJ`)S#{j zWpmU|t>LKlPf#s5Rb)I?%3K@1UN0j#`qG^~`w_j{e{OWhv-}>T19i)-JYv z04f*8qmpYS7R4Q?+_-`|u-@8wzWQd(YoT_}7}R!~iyH8^)=TK=!ea_bzT6GWTE|%1 zSVy7u`4ZF%Pog@$gX-`t>R`$Gk@@&Up(ZjMb>BqP1Q%I1quzJ$Blf@6=n@U;_^CB( zL$f61P}{B=YUYhl2T*6!5j+j`+){h}5T2%f20z6`jZ8oJ8=G7xff`U<)W@x3WA?v} z$N~1kG}OVf98=$F)&2ZIAlg4n##_n7uv$b+UeD z-R4nH@|{41@(k)I{u33Vcc=$)H8u58IG1`u)Ik40&E#KH4y0>l1`>&CuZ3Eg7O3|O zK}B+`t$VX6D3ps)GuVon!4aH*=dn08Yi{ZuYGzIgbCRV-op6DuNEJZ6APUuQ4O9eL zp(fZ3^^J)~BJVi~_QEaHO#ih8wKOvS`ZIZMK#%ljhq)?6v$56@m24`c|Hpb6U2Tx>MpVI={;#%B+K5Wv?=QP9S zmO0@8uk2T)HZI@-Q3^FIs`k=KCQcFPPSV#D3qCd z_?(Iuiu!1DK<$R!*bYZy3cQFK&=u6S`U^Fnzfm2h=xLIzE7qXC3M*g|PQpCBOzy1l zDCqmV4o~70EX10x>g{vhQ2(wEe``hkNME0GoBGRsK4%$-% zm~z80B+5;ri6kCZZYRP1cvkFxs1>yCQ95Bk6V zqbO*5oJ1W!N$5WZPy@+2&g4Q(RL6}`+1wK~pn<3ynSsio<*41U&9*0?a^ot7;uF*W z0>?9PWoak{y|6s$W7Gm&9E9p{2!`Wie2HIRHT<09)y!|B4w}DFp?-ymXwC^HNuyBp zSX3n1p!yw%-gFA%DJW}GPc$>>fy(L;sE#L~9{2>6#Y<4z>H=y%U%{Gq2layDlgxIm zh7r`8pzilj{Z6&cnZ*8A=$F!<5bm=kppMe3s3Y^X^*L$@e3Q)*fXdZ0S$r0atU z{TS3hXIPh_J~mrWFFa=3f4~CNe?xr(-lHPt<(+OuS{T(3i^}eLsDU&^C1*b@gi}#T zx(${6r%(e+vZk3~A{2qT?<1^&y-)+&U_ET~oJ8C32sPuBGmYWade;7^5YNWaxF3t* zLo9B!)Tc2QEWZh;xjv@L=T=p0EOJ{42PtB6Vp#LL-n&AM{TF$qwweGSW zK}GDW^^VnW7_|asO%qx+Gev*xplyL0+nND7O?*dQ%Iyip?-(jUO@}Z8b+e( z4XyoA+jE9>5$fDnhnmq>sL-B9E!EGc0snzIL0?%zJ~RE)`OF@bEofNJ4FgfX^Me-o zoHiJZ>iBSs543dL~>%Hm&99bQG9)%Q^Y@ohBqe5jCCKqc!;RK#|p za^!c^68JV5gHbtC7&UhFWW#3}fyeyWaJ{uLAWu zL?z>I7>y6H4(8ixX50_cP#=eS@ibI~=At5d5Vdp()2L=5zct`Xlp#g4XOkYOR8H zn6)f}dT~3{_3@~rnui*|HtdZ@QCVMjr-@Vp)PdCv6$uYDu<57?twFu`3na3h^A!bc zx1TT+@1sJMewS&_g-X&GRC`0znce{vvEi7Eb5OsCW`1dsb_r@p_oF88D{4UZQ3H66 z=@hH~C}>U7>^3vWg_?O~RJM1;jrb*MAZ_+=0tWD{z(nfD_nIVJ@|9W2EvQH(q9*n? zs=rKMo1~3G4LlapYOUH*&{wNFroeuvP<@Q*ARhS)I7?95vD5(*sivsyGz1lq>8Rba z7WMoV)Qk3_cFS4Rd#<9EFbO@~_>zLQQNTfC5H_Tq9|z)KRI*)1b@TxB+-p>5-EU0C z*-+;|9@J9QKnt3iC zk3j8;Ij9#LLcRDbDssQ029Rv)Sr41P;*COoavo;?Yv$8w&^}*kFYLky>IZNR-bICO z)VJoZ&pp)nu*-S_HS@qDX1|w3?Sd}Wai|C`L*>v$)WE*+C@7?fsBM&l3T?`xCbWU5 zwaSm`upBA^Eo^%aTOWn`y)Yg1g7v5u9zZ4Ecc=;8L-p?*GxvGvDHNg}irS}jPzOb4 z?1U##59B{?A`pQZa5VPA>R1i8V^w^Dx*mDL47@Vxv+90l#iWvDe= zkCFH_7Qs8Vp5>$&Ky}m^Uk|m`gHRC}i`pHZ+V*Xz96E@K+&K)xN47olcN!4;uOJ0= z6ytB;4~3{1x5ZHGf!fbgu_~@XCErbSF&T9*y+bWk##840Fswtp5^71NSeK$Au><{o z|96anUT^`6;$u`tIlnhcQUcXp3$>^`)lD$DkRLU$NvQ3$2(=V@ZTl75{s@(f>3=Z$JRFsLjZyda zvd;Q}{jX5&qCv@*fZ9ekQSGUJH1$xdPrWv3!1GW8NJQnzbJXrB@RP9)YM}kFGLFZx zcnFo$&ruO?cE&Rg3_N2-Iv2Gz`%we<5q0Bj>w8o(&kip)z?G6s1+n>8wfQ8ZLTt>rM(KxUwla|P-JTT#h&+_s-bot)QE2iYCe^RH0@ z%XrT86M~vZ6so_5s3q~*Q_vAS1QpVG)}5%eI)ge1pP@PkJ8%BiOC{9xL8xR~fSUO) zs2M-R1kCV@S)xnWJAfs<;Bz|S#~1mJ3jyrEGl}LxnO}X*H7=~U%)jAa{BQgcqQ+r7?AqIrA%GL+aB}k-mgYwg1!J zGAC4fYgbexdZX5AD(dWCi<;SHRI;5$<-!Bh%+uU9e-V)nmBg(v6vv?=yb2Y;!>Ic& zV;aZuO9}o3)`yMrrbEsT; ziJ_SGj?cM(MbXoU-ciukEazQw^3_8nTMN|pdI0JS|IA)rjyhO2qLOJ3DniGw7oNts zSn{6F*@8#00`|La2DSn9-W~VZ|N8hO(4Y|gjp{h_1M{cZ+^DtfiM??>>P*k@&}4l+ z)IKkYnqd`dQ*2MY2Wo&vQTLriO(Y4U@$N(RzaGr{$ZVHVsF~D2eFN&FmY^l-zMj@m zs0htM<-j`B1dgI6a2<93L#&DKF@R*P`Pf9F_7n5(3==&H-MHZ}Uc=D8ea=jLhwX62 zQaHn zo|itSD~~a%@1PEQ|_c2mWieXMR)!YNH0! z5A|FeYH3HJ|Ns9^qM*<&M7?;G{{q>GN}8h>iWgD){{^b!;J0Rm<*^v`x~Lo&hRTTr zsAS!RVR#BV6XCna%$>UL_^fOHkD{O()}dbT9cq97iKQ?Zwf~F1H`}H@D*1Y%A~Ftj zmQO?7w-P(zH>iGd@-t;3Rz%JGFe*}~(f|Mdu2N8kZ?F$$32^=Ydo3R4QGb9s>&N+A zf6{%9x_=L9$$rFwcny_=uIu`Ls1(Dk)XSj`s3hC|7E@49lfw1pQ)2*yHO z=!Ro(2A;;0DP5;4o<;4J$W*TXpIjGUPyqk-V||m_^=E&Ew5~Ir`^I2ACZm#dcskdA zKqaI4>6+eio%s|_rZ)|(Gq_F$Iy{K_SbU$+b}|j@_}o_kju74jfIxB@DwRSzYIA9D?e&NU-bw zm(P2s4mxLZ{eSD7I=k!tg;NRDVZ8MZR8m&Y;rf3$4MGj%0BT}cbGrT{^tw@KO~ZUV ziubVrev!-de6qF^cY@9`5U z%4Gc})JG$*wChaA0T_xeum)x;<2nnl9fsgztc;nWUFRNtgp09kS=aynht66Dlym+6 zY?m&^_5YPjKzY~c&%m1CX5Q}{s^B^+uxCXxV_zi`+7%egjpy+u*Y8wzoz&D5s+jG0 zKGt>K(q6qPp~l#1BpKJsRCk^2)VtO&1J7L3?1JViH*`TrO|DHF))U>}veO^;Eas5YZ5dKF!2fo8>OKti zQJ>%Wn2kuS!vyLFTbq+{N*gnQ6{!9bFdWaLzKU;9?@8meH78zH)Dc+`^I=O=Xh)$w zBGXW3_6jVDJ5e8--%vApgL*!wo!R%rQO~zQC37#-gq~n^e2w}Dc@^86Wb2O_(Hc}J zx1o;WL#Pnm!dOg3o&6O$nCx$c`o%LBbKy$V_5HXI&!KXxXGhb|3Dj5hH>2k~wikSz zOo(%$W)y*`unuY_jW7&5U?&`pF?bCtVz$oa#m!I=?1zffY}ChVKWakPP)nVniB`Ez6gp$&Zf0aFQCYni_5I(C+6}jHIcDi@4xH^+k>p$4!*wF?LQmH@$8}$C z*ExU}uo~^N`|z2@pZl6!aI>H5|1Y0i`%~A8vJNmK%Zv4?m%tDlg^h6uY6f?)8NNeB zs_8%znXXuvdOWIqopldJP(Oi+%2vH$bXFr0=7xB!*aSwA-0t2ExF zUK2}Ti8%9u_E?R2f7E{8jwLYxbp*dbW%<0puH(at*dKqzMp$Er$(i{>JX1JJ!)z|3 z8_LWH)e=-B_78KNF6a(7Csq#}LVY)C00l=Fdt)T^Em#GALnU9%k!Dxa#1YgxqjK#M zYRRvA6!fClQRbkSX`PR{aTzLU)?roLjf&WF)UL=f+H9u~)Do0NZPyN{$P7jOM4N*; zu-2lMayROJ?=%ISY)?@kOcigkxh#fJuWs#udhs;tdQ_GlM|GTtI_dth^~b2^-=m%j z8)F6%i<(eVWCEVkg@Tf15Nhqmqmpu^brULizC?BSBkF~ZPzTOC)C+QsH4`a^+Lj-o z2G|!Bk+HUY0WPAx3xl=)>x?t|x+CgWX%Ez|*}nKe0HH%A&${uh^ByykGurQ&CzzRh zh>BoQ)N`@6-V?Qp;;|Sm!~A#(m6Z1}CGU40QP5gHM~(a~YVC4PG&e?DV^AkqMbtsm z1vTK_sOJaR_TjdDtaYMopN6_`HfpIBq5tpyS5eRsY_T^SKqbv_)LDHI^}@TD4xgYp zNJfR$H_1dICu->mqwbHg_426xYM`ELiCV&rli2?%45C46=^+t!mZ8>e1uC>VQ6oQT z>t|3&l!O|nfr`j{TVIKq=|d8 zzpq|=K=jxgeTH-$+Ot|*Txj7qf3a&^TtxSe2NwC{&dY#(cV7AuGVa@%!o4)%|9v4L A0ssI2 delta 15923 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

Z{czbqN9>S5z9A3t8JXroqJK{aA z7f`GI6>0!}U)j|kih<-?q9WE6b>CEs!A01Qdar%O{_jFTy^)Uhm(3=uK|b{;=8z6G zM7>tqjCRZ|+>8oo!Wgy@*LR>+`Q5R0HHWgDHFb4StG*LvMwzBKh6QgrV`|(x)iLKOKRS)0 zoczM+j#)+i;SBo{n#Er)tCD|-6ENyq$NT@B*y$lLm4ZgI2o(=rK^+wO?rH!-QH$y@ zHsksOOzF!H&N+@bO}@r_$NMiEnG+o|nEZ$ZjyZ~t7xLQ1t&7-h4D6@Hj=4`g$A5Ip z8{E3oF*_;utXalfk!Zh?RgAq?+ppodYY8P4q*>>f2N=HIF^{>PW}~AmZQgEnynm!> zz12ph^)|=cq~a$y9+O#ttUuEziRZ~5*x{JBxMrv0{da<;yBu?v^=H1@%@+j+<%LwSCQZKi(`&sJBIxl3;f1Q3v=@D zDDErD#Y9|-xl(ZOoSO8S33U!+x?s0w3}z=kAM@Zg)JyFw>Yd?tkrP$>zXpj|oR9zDWz>E>dC5L7 z{jxpz_Pahobs)zT`!b0`9YkYM9bJf8?Q1Y4oUg{;9N`;|KuQ`6ud*pc${kL?IcKe6A8 zm9P`#&#?nGddl}c_isTqj5+ztMy$&V`;9pJ1^Ztw75|rx_a6$%p-!s5F%PDEWjhdo zdTX^oUGIxJ%g3TVM7Cf!UPFI${|?2{kkYgK$0S1pEmr z;lG#)D-dUOAQsg?Q`FqHck|s)NA3XBq8o|%a2~3|dr*rs88sz$QAcy#x9$zOU)vj_ zP#0>TUKV{&i|R*I#T&6C{>ROKK$eKfJg0Zz4^En-?nRP(eFpf<$sYNN;yGzc)bq*j UB(*8A-+w~p3cE8`aD4XtAI(Lo;{X5v delta 10876 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 N1h$SD5&SLb{{f}9x+VYs delta 24912 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 Date: Sun, 22 Dec 2019 12:24:09 +0100 Subject: [PATCH 137/162] Bumped up version number. --- version.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.inc b/version.inc index 4add49271e..dbd97b6554 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer") -set(SLIC3R_VERSION "2.2.0-alpha1") +set(SLIC3R_VERSION "2.2.0-alpha2") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_RC_VERSION "2,2,0,0") set(SLIC3R_RC_VERSION_DOTS "2.2.0.0") From e2fd540815cde2a88c34e3fd57630e38a93b8c35 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 13:52:47 +0100 Subject: [PATCH 138/162] Updated PrusaResearch.idx, so our in house customer will get updated profiles. --- resources/profiles/PrusaResearch.idx | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index 3b2720300e..c451bb8bf4 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,4 +1,5 @@ min_slic3r_version = 2.2.0-alpha0 +1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles. 1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0 min_slic3r_version = 2.1.1-beta0 1.0.6 Added Prusa MINI profiles From 4473254779e7e2722ef5d5bba842cf4510169a03 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 14:17:26 +0100 Subject: [PATCH 139/162] Trying to fix unit tests when targeting OSX 10.9. --- tests/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 458d398602..aab5401269 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,11 @@ add_library(Catch2 INTERFACE) list (APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/Catch2) target_include_directories(Catch2 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) add_library(Catch2::Catch2 ALIAS Catch2) +if (APPLE) + # OSX builds targeting OSX 10.9 do not support new std::uncought_exception() + # see https://github.com/catchorg/Catch2/issues/1218 + target_compile_definitions(Catch2 PUBLIC -DCATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) +endif() include(Catch) set(CATCH_EXTRA_ARGS "" CACHE STRING "Extra arguments for catch2 test suites.") From 220e2dbfec58cbbcff548d8211a17f0dcbe32aab Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 14:25:07 +0100 Subject: [PATCH 140/162] Fixed previous commit (change of CMake) --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aab5401269..61fe972772 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,7 +11,7 @@ add_library(Catch2::Catch2 ALIAS Catch2) if (APPLE) # OSX builds targeting OSX 10.9 do not support new std::uncought_exception() # see https://github.com/catchorg/Catch2/issues/1218 - target_compile_definitions(Catch2 PUBLIC -DCATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) + target_compile_definitions(Catch2 INTERFACE -DCATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) endif() include(Catch) From a2ff94515f660728cedac5ce3efd6fed08467dc5 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 2 Jan 2020 09:07:33 +0100 Subject: [PATCH 141/162] #3430 - Fixed crash when right-clicking on wipe tower --- src/slic3r/GUI/Plater.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ec44813813..8051b73ecd 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4098,7 +4098,11 @@ bool Plater::priv::can_reload_from_disk() const const GLVolume* v = selection.get_volume(idx); int v_idx = v->volume_idx(); if (v_idx >= 0) - selected_volumes.push_back({ v->object_idx(), v_idx }); + { + int o_idx = v->object_idx(); + if ((0 <= o_idx) && (o_idx < (int)model.objects.size())) + selected_volumes.push_back({ o_idx, v_idx }); + } } std::sort(selected_volumes.begin(), selected_volumes.end()); selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end()), selected_volumes.end()); From 3d5e32a8768fe7ee7c89ee259c27d3f83c2b45a8 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 2 Jan 2020 11:37:50 +0100 Subject: [PATCH 142/162] #3435 - Added object's instances count into Slic3r_PE_model.config inside exported .3mf files --- src/libslic3r/Format/3mf.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 376b34ca8a..b485e83d86 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -87,6 +87,7 @@ const char* V3_ATTR = "v3"; const char* OBJECTID_ATTR = "objectid"; const char* TRANSFORM_ATTR = "transform"; const char* PRINTABLE_ATTR = "printable"; +const char* INSTANCESCOUNT_ATTR = "instances_count"; const char* KEY_ATTR = "key"; const char* VALUE_ATTR = "value"; @@ -1613,6 +1614,9 @@ namespace Slic3r { return false; } + // Added because of github #3435, currently not used by PrusaSlicer + int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR); + m_objects_metadata.insert(IdToMetadataMap::value_type(object_id, ObjectMetadata())); m_curr_config.object_id = object_id; return true; @@ -2495,7 +2499,8 @@ namespace Slic3r { const ModelObject* obj = obj_metadata.second.object; if (obj != nullptr) { - stream << " <" << OBJECT_TAG << " id=\"" << obj_metadata.first << "\">\n"; + // Output of instances count added because of github #3435, currently not used by PrusaSlicer + stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n"; // stores object's name if (!obj->name.empty()) From 51ca7cbdfe272be5a183b9f532a25020af20e30a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 2 Jan 2020 11:56:48 +0100 Subject: [PATCH 143/162] #3385 - Increased max sensitivity for 3Dconnexion devices --- src/slic3r/GUI/Mouse3DController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index ad5be88d8c..a4c9ef2554 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -311,11 +311,11 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign ImGui::PopStyleColor(); float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale; - if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f")) + if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 5.0f, "%.1f")) m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale); float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale; - if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f")) + if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 5.0f, "%.1f")) m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale); ImGui::Separator(); From 095b50cc04b3dc572f9e1ade99647f56d1a59dd2 Mon Sep 17 00:00:00 2001 From: Italo Soares Date: Tue, 24 Dec 2019 00:01:11 -0300 Subject: [PATCH 144/162] Added a step by step guide I have added a step by step guide at the end of the original, i had tons of issued for lack of knowledge on how to work with visual studio, this guide has been provided by @douggorgen and helped me to make it work. --- doc/How to build - Windows.md | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/doc/How to build - Windows.md b/doc/How to build - Windows.md index b8829047bf..c2dc31ce31 100644 --- a/doc/How to build - Windows.md +++ b/doc/How to build - Windows.md @@ -120,3 +120,49 @@ Refer to the CMake scripts inside the `deps` directory to see which dependencies \*) Specifically, the problem arises when building boost. Boost build tool appends all build options into paths of intermediate files, which are not handled correctly by either `b2.exe` or possibly `ninja` (?). + + +# Noob guide (step by step) + +Install Visual Studio Community 2019 from +visualstudio.microsoft.com/vs/ +Select all workload options for C++ + +Install git for Windows from +gitforwindows.org +download and run the exe accepting all defaults + +download PrusaSlicer-master.zip from github +I downloaded this to c:\PrusaSlicer and unzipped to c:\PrusaSlicer\PrusaSlicer-master\ so this will be my prefix for all my steps. Substitute your prefix. + +Go to the Windows Start Menu and Click on "Visual Studio 2019" folder, then select the ->"x64 Native Tools Command Prompt" to open a command window + +cd c:\PrusaSlicer\PrusaSlicer-master\deps + +mkdir build + +cd build + +cmake .. -G "Visual Studio 16 2019" -DDESTDIR="c:\PrusaSlicer\PrusaSlicer-master" + +msbuild /m ALL_BUILD.vcxproj // This took 13.5 minutes on my machine: core I7-7700K @ 4.2Ghz with 32GB main memory and 20min on a average laptop + +cd c:\PrusaSlicer\PrusaSlicer-master\ + +mkdir build + +cd build + +cmake .. -G "Visual Studio 16 2019" -DCMAKE_PREFIX_PATH="c:\PrusaSlicer\PrusaSlicer-master\usr\local" + +open Visual Studio for c++ development (VS asks this the first time you start it) + +Open->Project/Solution or File->Open->Project/Solution (depending on which dialog comes up first) + +click on c:\PrusaSlicer\PrusaSlicer-master\build\PrusaSlicer.sln + +Debug->Start Debugging or Debug->Start Without debugging +PrusaSlicer should start. You're up and running! + + +note: Thanks to @douggorgen for the original guide, as an answer for a issue From 9f529e86ccb75fe49ddbb58ec39e0c84f600bcdb Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 30 Dec 2019 15:56:51 +0100 Subject: [PATCH 145/162] Fixed filaments/materials preset list updating from ConfigWizard if list of printers was changed but filaments/sal_materials page wasn't activated --- src/slic3r/GUI/ConfigWizard.cpp | 29 ++++++++++++++++++++----- src/slic3r/GUI/ConfigWizard_private.hpp | 3 ++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 971bd1f1d3..265e7f203a 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1605,7 +1605,27 @@ void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool i load_pages(); } -bool ConfigWizard::priv::check_material_config(Technology technology) +bool ConfigWizard::priv::on_bnt_finish() +{ + /* When Filaments or Sla Materials pages are activated, + * materials for this pages are automaticaly updated and presets are reloaded. + * + * But, if _Finish_ button was clicked without activation of those pages + * (for example, just some printers were added/deleted), + * than last changes wouldn't be updated for filaments/materials. + * SO, do that before close of Wizard + */ + update_materials(T_ANY); + if (any_fff_selected) + page_filaments->reload_presets(); + if (any_sla_selected) + page_sla_materials->reload_presets(); + + // check, that there is selected at least one filament/material + return check_materials_in_config(T_ANY); +} + +bool ConfigWizard::priv::check_materials_in_config(Technology technology) { const auto exist_preset = [this](const std::string& section, const Materials& materials) { @@ -1899,16 +1919,15 @@ ConfigWizard::ConfigWizard(wxWindow *parent) // check, that there is selected at least one filament/material ConfigWizardPage* active_page = this->p->index->active_page(); if ( (active_page == p->page_filaments || active_page == p->page_sla_materials) - && !p->check_material_config(dynamic_cast(active_page)->materials->technology)) + && !p->check_materials_in_config(dynamic_cast(active_page)->materials->technology)) return; this->p->index->go_next(); }); p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { - if (!p->check_material_config(T_ANY)) - return; - this->EndModal(wxID_OK); + if (p->on_bnt_finish()) + this->EndModal(wxID_OK); }); p->btn_sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index fc91909e71..a90832a3fc 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -489,7 +489,8 @@ struct ConfigWizard::priv void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt); void on_3rdparty_install(const VendorProfile *vendor, bool install); - bool check_material_config(Technology technology); + bool on_bnt_finish(); + bool check_materials_in_config(Technology technology); void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); // #ys_FIXME_alise void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add); From 0d9022c5f6bc05154819617a72fae884776eada0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 2 Jan 2020 16:40:32 +0100 Subject: [PATCH 146/162] Implemented "renamed_from" attribute of a system profile, so that references from user profiles and .3mfs / .amfs to system profiles are not being lost. If a system profile has no "renamed_from" profile name assigned, and the system profile name contains "@", then a profile name with the "@" is implicitely assumed to be the name, from which this profile has been renamed. --- src/slic3r/GUI/Preset.cpp | 55 ++++++++++++++++++++++--------- src/slic3r/GUI/Preset.hpp | 20 +++++++++++- src/slic3r/GUI/PresetBundle.cpp | 58 +++++++++++++++++++++------------ 3 files changed, 97 insertions(+), 36 deletions(-) diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 1c848b60fa..c2439b26f4 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -590,6 +590,7 @@ void PresetCollection::reset(bool delete_files) m_presets.erase(m_presets.begin() + m_num_default_presets, m_presets.end()); this->select_preset(0); } + m_map_system_profile_renamed.clear(); } void PresetCollection::add_default_preset(const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name) @@ -703,6 +704,11 @@ Preset& PresetCollection::load_external_preset( // Is there a preset already loaded with the name stored inside the config? std::deque::iterator it = this->find_preset_internal(original_name); bool found = it != m_presets.end() && it->name == original_name; + if (! found) { + // Try to match the original_name against the "renamed_from" profile names of loaded system profiles. + it = this->find_preset_renamed(original_name); + found = it != m_presets.end(); + } if (found && profile_print_params_same(it->config, cfg)) { // The preset exists and it matches the values stored inside config. if (select) @@ -872,24 +878,27 @@ const Preset* PresetCollection::get_selected_preset_parent() const if (this->get_selected_idx() == -1) // This preset collection has no preset activated yet. Only the get_edited_preset() is valid. return nullptr; -// const std::string &inherits = this->get_edited_preset().inherits(); -// if (inherits.empty()) -// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; - std::string inherits = this->get_edited_preset().inherits(); - if (inherits.empty()) - { - if (this->get_selected_preset().is_system || this->get_selected_preset().is_default) - return &this->get_selected_preset(); - if (this->get_selected_preset().is_external) + const Preset &selected_preset = this->get_selected_preset(); + if (selected_preset.is_system || selected_preset.is_default) + return &selected_preset; + + const Preset &edited_preset = this->get_edited_preset(); + const std::string &inherits = edited_preset.inherits(); + const Preset *preset = nullptr; + if (inherits.empty()) { + if (selected_preset.is_external) return nullptr; - - inherits = m_type != Preset::Type::TYPE_PRINTER ? "- default -" : - this->get_edited_preset().printer_technology() == ptFFF ? - "- default FFF -" : "- default SLA -" ; + preset = &this->default_preset(m_type == Preset::Type::TYPE_PRINTER && edited_preset.printer_technology() == ptSLA ? 1 : 0); + } else + preset = this->find_preset(inherits, false); + if (preset == nullptr) { + // Resolve the "renamed_from" field. + assert(! inherits.empty()); + auto it = this->find_preset_renamed(inherits); + if (it != m_presets.end()) + preset = &(*it); } - - const Preset* preset = this->find_preset(inherits, false); return (preset == nullptr/* || preset->is_default*/ || preset->is_external) ? nullptr : preset; } @@ -900,6 +909,11 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const // return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; return nullptr; const Preset* preset = this->find_preset(inherits, false); + if (preset == nullptr) { + auto it = this->find_preset_renamed(inherits); + if (it != m_presets.end()) + preset = &(*it); + } return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset; } @@ -1402,6 +1416,17 @@ std::vector PresetCollection::merge_presets(PresetCollection &&othe return duplicates; } +void PresetCollection::update_map_system_profile_renamed() +{ + m_map_system_profile_renamed.clear(); + for (Preset &preset : m_presets) + for (const std::string &renamed_from : preset.renamed_from) { + const auto [it, success] = m_map_system_profile_renamed.insert(std::pair(renamed_from, preset.name)); + if (! success) + BOOST_LOG_TRIVIAL(error) << boost::format("Preset name \"%1%\" was marked as renamed from \"%2%\", though preset name \"%3%\" was marked as renamed from \"%2%\" as well.") % preset.name % renamed_from % it->second; + } +} + std::string PresetCollection::name() const { switch (this->type()) { diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 785f52c429..547814559c 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -163,6 +163,10 @@ public: // Alias of the preset std::string alias = ""; + // List of profile names, from which this profile was renamed at some point of time. + // This list is then used to match profiles by their names when loaded from .gcode, .3mf, .amf, + // and to match the "inherits" field of user profiles with updated system profiles. + std::vector renamed_from; void save(); @@ -333,7 +337,8 @@ public: // The parent preset may be a system preset or a user preset, which will be // reflected by the UI. const Preset* get_selected_preset_parent() const; - // get parent preset for some child preset + // Get parent preset for a child preset, based on the "inherits" field of a child, + // where the "inherits" profile name is searched for in both m_presets and m_map_system_profile_renamed. const Preset* get_preset_parent(const Preset& child) const; // Return the selected preset including the user modifications. Preset& get_edited_preset() { return m_edited_preset; } @@ -465,6 +470,9 @@ protected: // Merge one vendor's presets with the other vendor's presets, report duplicates. std::vector merge_presets(PresetCollection &&other, const VendorMap &new_vendors); + // Update m_map_system_profile_renamed from loaded system profiles. + void update_map_system_profile_renamed(); + private: PresetCollection(); PresetCollection(const PresetCollection &other); @@ -490,6 +498,14 @@ private: } std::deque::const_iterator find_preset_internal(const std::string &name) const { return const_cast(this)->find_preset_internal(name); } + std::deque::iterator find_preset_renamed(const std::string &name) { + auto it_renamed = m_map_system_profile_renamed.find(name); + auto it = (it_renamed == m_map_system_profile_renamed.end()) ? m_presets.end() : this->find_preset_internal(it_renamed->second); + assert((it_renamed == m_map_system_profile_renamed.end()) || (it != m_presets.end() && it->name == it_renamed->second)); + return it; + } + std::deque::const_iterator find_preset_renamed(const std::string &name) const + { return const_cast(this)->find_preset_renamed(name); } size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible); @@ -501,6 +517,8 @@ private: // Use deque to force the container to allocate an object per each entry, // so that the addresses of the presets don't change during resizing of the container. std::deque m_presets; + // Map from old system profile name to a current system profile name. + std::map m_map_system_profile_renamed; // Initially this preset contains a copy of the selected preset. Later on, this copy may be modified by the user. Preset m_edited_preset; // Selected preset. diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index dbfd446b11..3ede7a4e06 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -288,6 +288,11 @@ std::string PresetBundle::load_system_presets() // No config bundle loaded, reset. this->reset(false); } + this->prints .update_map_system_profile_renamed(); + this->sla_prints .update_map_system_profile_renamed(); + this->filaments .update_map_system_profile_renamed(); + this->sla_materials.update_map_system_profile_renamed(); + this->printers .update_map_system_profile_renamed(); return errors_cummulative; } @@ -1132,7 +1137,6 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla PresetCollection *presets = nullptr; std::vector *loaded = nullptr; std::string preset_name; - std::string alias_name; if (boost::starts_with(section.first, "print:")) { presets = &this->prints; loaded = &loaded_prints; @@ -1141,12 +1145,6 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla presets = &this->filaments; loaded = &loaded_filaments; preset_name = section.first.substr(9); - - for (const auto& item : section.second) - if (boost::starts_with(item.first, "alias")) { - alias_name = item.second.data(); - break; - } } else if (boost::starts_with(section.first, "sla_print:")) { presets = &this->sla_prints; loaded = &loaded_sla_prints; @@ -1155,9 +1153,6 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla presets = &this->sla_materials; loaded = &loaded_sla_materials; preset_name = section.first.substr(13); - - int end_pos = preset_name.find_first_of("0."); - alias_name = preset_name.substr(0, end_pos-1); } else if (boost::starts_with(section.first, "printer:")) { presets = &this->printers; loaded = &loaded_printers; @@ -1213,19 +1208,32 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla // Load the print, filament or printer preset. const DynamicPrintConfig *default_config = nullptr; DynamicPrintConfig config; + std::string alias_name; + std::vector renamed_from; + auto parse_config_section = [§ion, &alias_name, &renamed_from, &path](DynamicPrintConfig &config) { + for (auto &kvp : section.second) { + if (kvp.first == "alias") + alias_name = kvp.second.data(); + else if (kvp.first == "renamed_from") { + if (! unescape_strings_cstyle(kvp.second.data(), renamed_from)) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" << + section.first << "\" contains invalid \"renamed_from\" key, which is being ignored."; + } + } + config.set_deserialize(kvp.first, kvp.second.data()); + } + }; if (presets == &this->printers) { // Select the default config based on the printer_technology field extracted from kvp. DynamicPrintConfig config_src; - for (auto &kvp : section.second) - config_src.set_deserialize(kvp.first, kvp.second.data()); + parse_config_section(config_src); default_config = &presets->default_preset_for(config_src).config; config = *default_config; config.apply(config_src); } else { default_config = &presets->default_preset().config; config = *default_config; - for (auto &kvp : section.second) - config.set_deserialize(kvp.first, kvp.second.data()); + parse_config_section(config); } Preset::normalize(config); // Report configuration fields, which are misplaced into a wrong group. @@ -1304,12 +1312,22 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla loaded.vendor = vendor_profile; } - // next step of an preset name aliasing - int end_pos = preset_name.find_first_of("@"); - if (end_pos != std::string::npos) - alias_name = preset_name.substr(0, end_pos - 1); - - loaded.alias = alias_name.empty() ? preset_name : alias_name; + // Derive the profile logical name aka alias from the preset name if the alias was not stated explicitely. + if (alias_name.empty()) { + int end_pos = preset_name.find_first_of("@"); + if (end_pos != std::string::npos) { + alias_name = preset_name.substr(0, end_pos); + if (renamed_from.empty()) + // Add the preset name with the '@' character removed into the "renamed_from" list. + renamed_from.emplace_back(alias_name + preset_name.substr(end_pos + 1)); + boost::trim_right(alias_name); + } + } + if (alias_name.empty()) + loaded.alias = preset_name; + else + loaded.alias = std::move(alias_name); + loaded.renamed_from = std::move(renamed_from); ++ presets_loaded; } From 3fb9fd4e30e16afe4a41aa4b6d5417e54fac6674 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 3 Jan 2020 10:01:27 +0100 Subject: [PATCH 147/162] #3389 - Added logging of detected 3Dconnexion device --- src/slic3r/GUI/Mouse3DController.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index a4c9ef2554..20eaa3d91c 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -619,15 +619,12 @@ bool Mouse3DController::connect_device() hid_get_product_string(m_device, product.data(), 1024); m_device_str += "/" + boost::nowide::narrow(product.data()); - BOOST_LOG_TRIVIAL(info) << "Connected device: " << m_device_str; - -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << std::endl << "Connected device:" << std::endl; - std::cout << "Manufacturer/product: " << m_device_str << std::endl; - std::cout << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")" << std::endl; - std::cout << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")" << std::endl; - std::cout << "Path................: '" << path << "'" << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + BOOST_LOG_TRIVIAL(info) << "Connected 3DConnexion device:"; + BOOST_LOG_TRIVIAL(info) << "Manufacturer/product: " << m_device_str; + BOOST_LOG_TRIVIAL(info) << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")"; + BOOST_LOG_TRIVIAL(info) << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")"; + if (!path.empty()) + BOOST_LOG_TRIVIAL(info) << "Path................: '" << path << "'"; // get device parameters from the config, if present double translation_speed = 1.0; From a4ad0a0925bbe52d2a1f69510664a69251caac53 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 3 Jan 2020 11:41:29 +0100 Subject: [PATCH 148/162] Fixed unresponsive 3Dconnexion device when switching to preview --- src/slic3r/GUI/GUI_Preview.cpp | 5 ----- src/slic3r/GUI/GUI_Preview.hpp | 1 - src/slic3r/GUI/Mouse3DController.cpp | 14 ++++++-------- src/slic3r/GUI/Mouse3DController.hpp | 5 ++--- src/slic3r/GUI/Plater.cpp | 17 ++++++++++++++++- src/slic3r/GUI/Plater.hpp | 2 ++ 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 2eb316be0f..1a4d12d316 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -341,11 +341,6 @@ void Preview::set_number_extruders(unsigned int number_extruders) } } -void Preview::set_canvas_as_dirty() -{ - m_canvas->set_as_dirty(); -} - void Preview::set_enabled(bool enabled) { m_enabled = enabled; diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index b0dac4223d..92ec15b22b 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -116,7 +116,6 @@ public: void set_as_dirty(); void set_number_extruders(unsigned int number_extruders); - void set_canvas_as_dirty(); void set_enabled(bool enabled); void bed_shape_changed(); void select_view(const std::string& direction); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 20eaa3d91c..e91b6175f8 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -112,7 +112,7 @@ void Mouse3DController::State::append_button(unsigned int id) bool Mouse3DController::State::process_mouse_wheel() { - if (m_mouse_wheel_counter == 0) + if (m_mouse_wheel_counter.load() == 0) return false; else if (!m_rotation.queue.empty()) { @@ -120,7 +120,7 @@ bool Mouse3DController::State::process_mouse_wheel() return true; } - m_mouse_wheel_counter = 0; + m_mouse_wheel_counter.store(0); return true; } @@ -229,8 +229,6 @@ bool Mouse3DController::apply(Camera& camera) if (!m_initialized) return false; - std::lock_guard lock(m_mutex); - // check if the user unplugged the device if (!m_running && is_device_connected()) { @@ -393,7 +391,7 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign bool Mouse3DController::connect_device() { - static const long long DETECTION_TIME_MS = 2000; // seconds + static const long long DETECTION_TIME_MS = 2000; // two seconds if (is_device_connected()) return false; @@ -694,7 +692,6 @@ void Mouse3DController::run() collect_input(); } } - void Mouse3DController::collect_input() { DataPacket packet = { 0 }; @@ -709,8 +706,6 @@ void Mouse3DController::collect_input() if (!wxGetApp().IsActive()) return; - std::lock_guard lock(m_mutex); - bool updated = false; if (res == 7) @@ -726,8 +721,11 @@ void Mouse3DController::collect_input() #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT if (updated) + { + wxGetApp().plater()->set_current_canvas_as_dirty(); // ask for an idle event to update 3D scene wxWakeUpIdle(); + } } bool Mouse3DController::handle_packet(const DataPacket& packet) diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index 543c44e775..9e5161ee7d 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -72,7 +72,7 @@ class Mouse3DController // Mouse3DController::collect_input() through the call to the append_rotation() method // GLCanvas3D::on_mouse_wheel() through the call to the process_mouse_wheel() method // GLCanvas3D::on_idle() through the call to the apply() method - unsigned int m_mouse_wheel_counter; + std::atomic m_mouse_wheel_counter; #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT size_t m_translation_queue_max_size; @@ -128,7 +128,6 @@ class Mouse3DController bool m_initialized; mutable State m_state; - std::mutex m_mutex; std::thread m_thread; hid_device* m_device; std::string m_device_str; @@ -151,7 +150,7 @@ public: bool is_device_connected() const { return m_device != nullptr; } bool is_running() const { return m_running; } - bool process_mouse_wheel() { std::lock_guard lock(m_mutex); return m_state.process_mouse_wheel(); } + bool process_mouse_wheel() { return m_state.process_mouse_wheel(); } bool apply(Camera& camera); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8051b73ecd..b0fb3f0e68 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1855,6 +1855,8 @@ struct Plater::priv bool is_preview_loaded() const { return preview->is_loaded(); } bool is_view3D_shown() const { return current_panel == view3D; } + void set_current_canvas_as_dirty(); + #if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool init_view_toolbar(); #endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX @@ -3472,7 +3474,7 @@ void Plater::priv::set_current_panel(wxPanel* panel) // keeps current gcode preview, if any preview->reload_print(true); - preview->set_canvas_as_dirty(); + preview->set_as_dirty(); view_toolbar.select_item("Preview"); } @@ -3985,6 +3987,14 @@ bool Plater::priv::complit_init_part_menu() return true; } +void Plater::priv::set_current_canvas_as_dirty() +{ + if (current_panel == view3D) + view3D->set_as_dirty(); + else if (current_panel == preview) + preview->set_as_dirty(); +} + #if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX bool Plater::priv::init_view_toolbar() #else @@ -5368,6 +5378,11 @@ BoundingBoxf Plater::bed_shape_bb() const return p->bed_shape_bb(); } +void Plater::set_current_canvas_as_dirty() +{ + p->set_current_canvas_as_dirty(); +} + PrinterTechnology Plater::printer_technology() const { return p->printer_technology; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index d9a9af3763..4793977058 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -240,6 +240,8 @@ public: GLCanvas3D* canvas3D(); BoundingBoxf bed_shape_bb() const; + void set_current_canvas_as_dirty(); + PrinterTechnology printer_technology() const; void set_printer_technology(PrinterTechnology printer_technology); From 3d17543d4049283f68a0c79b189175328ed745f7 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 3 Jan 2020 14:05:56 +0100 Subject: [PATCH 149/162] Fix of "Don't use bridging perimeters on top of elephant-foot compensation #3011" If the Elephant foot compensation is applied to the 1st object's layer, the uncompensated 1st object's slice is newly used for calculation of bridges, overhans, skirt, brim, raft and supports. Layer::slices were renamed to Layer::lslices to simplify reading of the code, to differentiate from LayerRegion::slices. --- src/libslic3r/GCode.cpp | 24 ++-- src/libslic3r/Layer.cpp | 14 +- src/libslic3r/Layer.hpp | 16 ++- src/libslic3r/LayerRegion.cpp | 6 +- src/libslic3r/Print.cpp | 4 +- src/libslic3r/Print.hpp | 2 +- src/libslic3r/PrintObject.cpp | 206 ++++++++++++++++-------------- src/libslic3r/SupportMaterial.cpp | 23 ++-- 8 files changed, 158 insertions(+), 137 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 433422d997..40ca7b0748 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -122,21 +122,21 @@ Polygons AvoidCrossingPerimeters::collect_contours_all_layers(const PrintObjectP const Layer* layer1 = object->layers()[i * 2]; const Layer* layer2 = object->layers()[i * 2 + 1]; Polygons polys; - polys.reserve(layer1->slices.size() + layer2->slices.size()); - for (const ExPolygon &expoly : layer1->slices) + polys.reserve(layer1->lslices.size() + layer2->lslices.size()); + for (const ExPolygon &expoly : layer1->lslices) //FIXME no holes? polys.emplace_back(expoly.contour); - for (const ExPolygon &expoly : layer2->slices) + for (const ExPolygon &expoly : layer2->lslices) //FIXME no holes? polys.emplace_back(expoly.contour); polygons_per_layer[i] = union_(polys); - } - }); + } + }); if (object->layers().size() & 1) { const Layer *layer = object->layers().back(); Polygons polys; - polys.reserve(layer->slices.size()); - for (const ExPolygon &expoly : layer->slices) + polys.reserve(layer->lslices.size()); + for (const ExPolygon &expoly : layer->lslices) //FIXME no holes? polys.emplace_back(expoly.contour); polygons_per_layer.back() = union_(polys); @@ -2006,8 +2006,8 @@ void GCode::process_layer( // - for each island, we extrude perimeters first, unless user set the infill_first // option // (Still, we have to keep track of regions because we need to apply their config) - size_t n_slices = layer.slices.size(); - const std::vector &layer_surface_bboxes = layer.slices_bboxes; + size_t n_slices = layer.lslices.size(); + const std::vector &layer_surface_bboxes = layer.lslices_bboxes; // Traverse the slices in an increasing order of bounding box size, so that the islands inside another islands are tested first, // so we can just test a point inside ExPolygon::contour and we may skip testing the holes. std::vector slices_test_order; @@ -2023,7 +2023,7 @@ void GCode::process_layer( const BoundingBox &bbox = layer_surface_bboxes[i]; return point(0) >= bbox.min(0) && point(0) < bbox.max(0) && point(1) >= bbox.min(1) && point(1) < bbox.max(1) && - layer.slices[i].contour.contains(point); + layer.lslices[i].contour.contains(point); }; for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) { @@ -2155,7 +2155,7 @@ void GCode::process_layer( m_config.apply(instance_to_print.print_object.config(), true); m_layer = layers[instance_to_print.layer_id].layer(); if (m_config.avoid_crossing_perimeters) - m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true)); + m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->lslices, true)); if (this->config().gcode_label_objects) gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n"; @@ -2476,7 +2476,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // Create the distance field for a layer below. const coord_t distance_field_resolution = coord_t(scale_(1.) + 0.5); *lower_layer_edge_grid = make_unique(); - (*lower_layer_edge_grid)->create(m_layer->lower_layer->slices, distance_field_resolution); + (*lower_layer_edge_grid)->create(m_layer->lower_layer->lslices, distance_field_resolution); (*lower_layer_edge_grid)->calculate_sdf(); #if 0 { diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 53a7f2fc45..505b01705e 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -47,8 +47,8 @@ void Layer::make_slices() slices = union_ex(slices_p); } - this->slices.clear(); - this->slices.reserve(slices.size()); + this->lslices.clear(); + this->lslices.reserve(slices.size()); // prepare ordering points Points ordering_points; @@ -61,19 +61,21 @@ void Layer::make_slices() // populate slices vector for (size_t i : order) - this->slices.push_back(std::move(slices[i])); + this->lslices.emplace_back(std::move(slices[i])); } // Merge typed slices into untyped slices. This method is used to revert the effects of detect_surfaces_type() called for posPrepareInfill. void Layer::merge_slices() { - if (m_regions.size() == 1) { + if (m_regions.size() == 1 && (this->id() > 0 || this->object()->config().elefant_foot_compensation.value == 0)) { // Optimization, also more robust. Don't merge classified pieces of layerm->slices, // but use the non-split islands of a layer. For a single region print, these shall be equal. - m_regions.front()->slices.set(this->slices, stInternal); + // Don't use this optimization on 1st layer with Elephant foot compensation applied, as this->lslices are uncompensated, + // while regions are compensated. + m_regions.front()->slices.set(this->lslices, stInternal); } else { for (LayerRegion *layerm : m_regions) - // without safety offset, artifacts are generated (GH #2494) + // without safety offset, artifacts are generated (upstream Slic3r GH #2494) layerm->slices.set(union_ex(to_polygons(std::move(layerm->slices.surfaces)), true), stInternal); } } diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 9a4297ce55..b7725d11da 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -106,12 +106,16 @@ public: coordf_t print_z; // Z used for printing in unscaled coordinates coordf_t height; // layer height in unscaled coordinates - // collection of expolygons generated by slicing the original geometry; - // also known as 'islands' (all regions and surface types are merged here) - // The slices are chained by the shortest traverse distance and this traversal - // order will be recovered by the G-code generator. - ExPolygons slices; - std::vector slices_bboxes; + // Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry + // (with possibly differing extruder ID and slicing parameters) and merged. + // For the first layer, if the ELephant foot compensation is applied, this lslice is uncompensated, therefore + // it includes the Elephant foot effect, thus it corresponds to the shape of the printed 1st layer. + // These lslices aka islands are chained by the shortest traverse distance and this traversal + // order will be applied by the G-code generator to the extrusions fitting into these lslices. + // These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important + // that the 1st lslice is not compensated by the Elephant foot compensation algorithm. + ExPolygons lslices; + std::vector lslices_bboxes; size_t region_count() const { return m_regions.size(); } const LayerRegion* get_region(int idx) const { return m_regions.at(idx); } diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 35acaf9983..f4f0d6a5de 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -72,7 +72,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec if (this->layer()->lower_layer != nullptr) // Cummulative sum of polygons over all the regions. - g.lower_slices = &this->layer()->lower_layer->slices; + g.lower_slices = &this->layer()->lower_layer->lslices; g.layer_id = (int)this->layer()->id(); g.ext_perimeter_flow = this->flow(frExternalPerimeter); @@ -139,7 +139,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly // Remove voids from fill_boundaries, that are not supported by the layer below. if (lower_layer_covered == nullptr) { lower_layer_covered = &lower_layer_covered_tmp; - lower_layer_covered_tmp = to_polygons(lower_layer->slices); + lower_layer_covered_tmp = to_polygons(lower_layer->lslices); } if (! lower_layer_covered->empty()) voids = diff(voids, *lower_layer_covered); @@ -260,7 +260,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly // of very thin (but still working) anchors, the grown expolygon would go beyond them BridgeDetector bd( initial, - lower_layer->slices, + lower_layer->lslices, this->flow(frInfill, true).scaled_width() ); #ifdef SLIC3R_DEBUG diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 1d4e69763e..02d9da7848 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1658,7 +1658,7 @@ void Print::_make_skirt() for (const Layer *layer : object->m_layers) { if (layer->print_z > skirt_height_z) break; - for (const ExPolygon &expoly : layer->slices) + for (const ExPolygon &expoly : layer->lslices) // Collect the outer contour points only, ignore holes for the calculation of the convex hull. append(object_points, expoly.contour.points); } @@ -1787,7 +1787,7 @@ void Print::_make_brim() Polygons islands; for (PrintObject *object : m_objects) { Polygons object_islands; - for (ExPolygon &expoly : object->m_layers.front()->slices) + for (ExPolygon &expoly : object->m_layers.front()->lslices) object_islands.push_back(expoly.contour); if (! object->support_layers().empty()) object->support_layers().front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON)); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 098049f1db..95c7b656a4 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -182,7 +182,7 @@ private: void _slice(const std::vector &layer_height_profile); std::string _fix_slicing_errors(); - void _simplify_slices(double distance); + void simplify_slices(double distance); bool has_support_material() const; void detect_surfaces_type(); void process_external_surfaces(); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index bf97baaf6f..8a59b6c3bf 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -117,7 +117,7 @@ void PrintObject::slice() BOOST_LOG_TRIVIAL(info) << warning; // Simplify slices if required. if (m_print->config().resolution) - this->_simplify_slices(scale_(this->print()->config().resolution)); + this->simplify_slices(scale_(this->print()->config().resolution)); // Update bounding boxes tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), @@ -125,10 +125,10 @@ void PrintObject::slice() for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { m_print->throw_if_canceled(); Layer &layer = *m_layers[layer_idx]; - layer.slices_bboxes.clear(); - layer.slices_bboxes.reserve(layer.slices.size()); - for (const ExPolygon &expoly : layer.slices) - layer.slices_bboxes.emplace_back(get_extents(expoly)); + layer.lslices_bboxes.clear(); + layer.lslices_bboxes.reserve(layer.lslices.size()); + for (const ExPolygon &expoly : layer.lslices) + layer.lslices_bboxes.emplace_back(get_extents(expoly)); } }); if (m_layers.empty()) @@ -242,13 +242,6 @@ void PrintObject::make_perimeters() m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end"; - /* - simplify slices (both layer and region slices), - we only need the max resolution for perimeters - ### This makes this method not-idempotent, so we keep it disabled for now. - ###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION); - */ - this->set_done(posPerimeters); } @@ -692,7 +685,7 @@ void PrintObject::detect_surfaces_type() if (upper_layer) { Polygons upper_slices = interface_shells ? to_polygons(upper_layer->get_region(idx_region)->slices.surfaces) : - to_polygons(upper_layer->slices); + to_polygons(upper_layer->lslices); surfaces_append(top, //FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice. offset_ex(offset_ex(diff_ex(layerm_slices_surfaces, upper_slices, true), -offset), offset), @@ -721,7 +714,7 @@ void PrintObject::detect_surfaces_type() surfaces_append( bottom, offset2_ex( - diff(layerm_slices_surfaces, to_polygons(lower_layer->slices), true), + diff(layerm_slices_surfaces, to_polygons(lower_layer->lslices), true), -offset, offset), surface_type_bottom_other); // if user requested internal shells, we need to identify surfaces @@ -733,7 +726,7 @@ void PrintObject::detect_surfaces_type() bottom, offset2_ex( diff( - intersection(layerm_slices_surfaces, to_polygons(lower_layer->slices)), // supported + intersection(layerm_slices_surfaces, to_polygons(lower_layer->lslices)), // supported to_polygons(lower_layer->get_region(idx_region)->slices.surfaces), true), -offset, offset), @@ -879,7 +872,7 @@ void PrintObject::process_external_surfaces() // Shrink the holes, let the layer above expand slightly inside the unsupported areas. polygons_append(voids, offset(surface.expolygon, unsupported_width)); } - surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->slices), voids); + surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->lslices), voids); } } ); @@ -985,8 +978,8 @@ void PrintObject::discover_vertical_shells() cache.bottom_surfaces = union_(cache.bottom_surfaces, false); // For a multi-material print, simulate perimeter / infill split as if only a single extruder has been used for the whole print. if (perimeter_offset > 0.) { - // The layer.slices are forced to merge by expanding them first. - polygons_append(cache.holes, offset(offset_ex(layer.slices, 0.3f * perimeter_min_spacing), - perimeter_offset - 0.3f * perimeter_min_spacing)); + // The layer.lslices are forced to merge by expanding them first. + polygons_append(cache.holes, offset(offset_ex(layer.lslices, 0.3f * perimeter_min_spacing), - perimeter_offset - 0.3f * perimeter_min_spacing)); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING { Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.slices)); @@ -1762,78 +1755,101 @@ end: ; BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - begin"; - tbb::parallel_for( - tbb::blocked_range(0, m_layers.size()), - [this, upscaled, clipped](const tbb::blocked_range& range) { - for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { - m_print->throw_if_canceled(); - Layer *layer = m_layers[layer_id]; - // Apply size compensation and perform clipping of multi-part objects. - float delta = float(scale_(m_config.xy_size_compensation.value)); - //FIXME only apply the compensation if no raft is enabled. - float elephant_foot_compensation = 0.f; - if (layer_id == 0 && m_config.raft_layers == 0) - // Only enable Elephant foot compensation if printing directly on the print bed. - elephant_foot_compensation = float(scale_(m_config.elefant_foot_compensation.value)); - if (layer->m_regions.size() == 1) { - // Optimized version for a single region layer. - if (layer_id == 0) { - if (delta > elephant_foot_compensation) { - delta -= elephant_foot_compensation; - elephant_foot_compensation = 0.f; - } else if (delta > 0) - elephant_foot_compensation -= delta; - } - if (delta != 0.f || elephant_foot_compensation > 0.f) { - // Single region, growing or shrinking. - LayerRegion *layerm = layer->m_regions.front(); - // Apply the XY compensation. - ExPolygons expolygons = (delta == 0.f) ? - to_expolygons(std::move(layerm->slices.surfaces)) : - offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta); - // Apply the elephant foot compensation. - if (elephant_foot_compensation > 0) - expolygons = union_ex(Slic3r::elephant_foot_compensation(expolygons, layerm->flow(frExternalPerimeter), unscale(elephant_foot_compensation))); - layerm->slices.set(std::move(expolygons), stInternal); - } - } else { - bool upscale = ! upscaled && delta > 0.f; - bool clip = ! clipped && m_config.clip_multipart_objects.value; - if (upscale || clip) { - // Multiple regions, growing or just clipping one region by the other. - // When clipping the regions, priority is given to the first regions. - Polygons processed; - for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { - LayerRegion *layerm = layer->m_regions[region_id]; - ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces)); - if (upscale) - slices = offset_ex(std::move(slices), delta); - if (region_id > 0 && clip) - // Trim by the slices of already processed regions. - slices = diff_ex(to_polygons(std::move(slices)), processed); - if (clip && (region_id + 1 < layer->m_regions.size())) - // Collect the already processed regions to trim the to be processed regions. - polygons_append(processed, slices); - layerm->slices.set(std::move(slices), stInternal); - } - } - if (delta < 0.f || elephant_foot_compensation > 0.f) { - // Apply the negative XY compensation. - Polygons trimming; - static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5); - if (elephant_foot_compensation > 0.f) { - trimming = to_polygons(Slic3r::elephant_foot_compensation(offset_ex(layer->merged(eps), std::min(delta, 0.f) - eps), - layer->m_regions.front()->flow(frExternalPerimeter), unscale(elephant_foot_compensation))); - } else - trimming = offset(layer->merged(float(SCALED_EPSILON)), delta - float(SCALED_EPSILON)); - for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) - layer->m_regions[region_id]->trim_surfaces(trimming); - } - } - // Merge all regions' slices to get islands, chain them by a shortest path. - layer->make_slices(); - } - }); + { + // Compensation value, scaled. + const float xy_compensation_scaled = float(scale_(m_config.xy_size_compensation.value)); + const float elephant_foot_compensation_scaled = (m_config.raft_layers == 0) ? + // Only enable Elephant foot compensation if printing directly on the print bed. + float(scale_(m_config.elefant_foot_compensation.value)) : + 0.f; + // Uncompensated slices for the first layer in case the Elephant foot compensation is applied. + ExPolygons lslices_1st_layer; + tbb::parallel_for( + tbb::blocked_range(0, m_layers.size()), + [this, upscaled, clipped, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer] + (const tbb::blocked_range& range) { + for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { + m_print->throw_if_canceled(); + Layer *layer = m_layers[layer_id]; + // Apply size compensation and perform clipping of multi-part objects. + float elfoot = (layer_id == 0) ? elephant_foot_compensation_scaled : 0.f; + if (layer->m_regions.size() == 1) { + assert(! upscaled); + assert(! clipped); + // Optimized version for a single region layer. + // Single region, growing or shrinking. + LayerRegion *layerm = layer->m_regions.front(); + if (elfoot > 0) { + // Apply the elephant foot compensation and store the 1st layer slices without the Elephant foot compensation applied. + lslices_1st_layer = to_expolygons(std::move(layerm->slices.surfaces)); + float delta = xy_compensation_scaled; + if (delta > elfoot) { + delta -= elfoot; + elfoot = 0.f; + } else if (delta > 0) + elfoot -= delta; + layerm->slices.set( + union_ex( + Slic3r::elephant_foot_compensation( + (delta == 0.f) ? lslices_1st_layer : offset_ex(lslices_1st_layer, delta), + layerm->flow(frExternalPerimeter), unscale(elfoot))), + stInternal); + if (xy_compensation_scaled != 0.f) + lslices_1st_layer = offset_ex(std::move(lslices_1st_layer), xy_compensation_scaled); + } else if (xy_compensation_scaled != 0.f) { + // Apply the XY compensation. + layerm->slices.set( + offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), xy_compensation_scaled), + stInternal); + } + } else { + bool upscale = ! upscaled && xy_compensation_scaled > 0.f; + bool clip = ! clipped && m_config.clip_multipart_objects.value; + if (upscale || clip) { + // Multiple regions, growing or just clipping one region by the other. + // When clipping the regions, priority is given to the first regions. + Polygons processed; + for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { + LayerRegion *layerm = layer->m_regions[region_id]; + ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces)); + if (upscale) + slices = offset_ex(std::move(slices), xy_compensation_scaled); + if (region_id > 0 && clip) + // Trim by the slices of already processed regions. + slices = diff_ex(to_polygons(std::move(slices)), processed); + if (clip && (region_id + 1 < layer->m_regions.size())) + // Collect the already processed regions to trim the to be processed regions. + polygons_append(processed, slices); + layerm->slices.set(std::move(slices), stInternal); + } + } + if (xy_compensation_scaled < 0.f || elfoot > 0.f) { + // Apply the negative XY compensation. + Polygons trimming; + static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5); + if (elfoot > 0.f) { + lslices_1st_layer = offset_ex(layer->merged(eps), std::min(xy_compensation_scaled, 0.f) - eps); + trimming = to_polygons(Slic3r::elephant_foot_compensation(lslices_1st_layer, + layer->m_regions.front()->flow(frExternalPerimeter), unscale(elfoot))); + } else + trimming = offset(layer->merged(float(SCALED_EPSILON)), xy_compensation_scaled - float(SCALED_EPSILON)); + for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) + layer->m_regions[region_id]->trim_surfaces(trimming); + } + } + // Merge all regions' slices to get islands, chain them by a shortest path. + layer->make_slices(); + } + }); + if (elephant_foot_compensation_scaled > 0.f) { + // The Elephant foot has been compensated, therefore the 1st layer's lslices are shrank with the Elephant foot compensation value. + // Store the uncompensated value there. + assert(! m_layers.empty()); + assert(m_layers.front()->id() == 0); + m_layers.front()->lslices = std::move(lslices_1st_layer); + } + } + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end"; } @@ -2131,7 +2147,7 @@ std::string PrintObject::_fix_slicing_errors() BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end"; // remove empty layers from bottom - while (! m_layers.empty() && m_layers.front()->slices.empty()) { + while (! m_layers.empty() && (m_layers.front()->lslices.empty() || m_layers.front()->empty())) { delete m_layers.front(); m_layers.erase(m_layers.begin()); m_layers.front()->lower_layer = nullptr; @@ -2147,7 +2163,7 @@ std::string PrintObject::_fix_slicing_errors() // Simplify the sliced model, if "resolution" configuration parameter > 0. // The simplification is problematic, because it simplifies the slices independent from each other, // which makes the simplified discretization visible on the object surface. -void PrintObject::_simplify_slices(double distance) +void PrintObject::simplify_slices(double distance) { BOOST_LOG_TRIVIAL(debug) << "Slicing objects - siplifying slices in parallel - begin"; tbb::parallel_for( @@ -2160,9 +2176,9 @@ void PrintObject::_simplify_slices(double distance) layer->m_regions[region_idx]->slices.simplify(distance); { ExPolygons simplified; - for (const ExPolygon& expoly : layer->slices) + for (const ExPolygon &expoly : layer->lslices) expoly.simplify(distance, &simplified); - layer->slices = std::move(simplified); + layer->lslices = std::move(simplified); } } }); @@ -2194,7 +2210,7 @@ void PrintObject::clip_fill_surfaces() // Detect things that we need to support. // Cummulative slices. Polygons slices; - polygons_append(slices, layer->slices); + polygons_append(slices, layer->lslices); // Cummulative fill surfaces. Polygons fill_surfaces; // Solid surfaces to be supported. diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 179b35f59e..1d98bb0e62 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -1,6 +1,5 @@ #include "ClipperUtils.hpp" #include "ExtrusionEntityCollection.hpp" -#include "PerimeterGenerator.hpp" #include "Layer.hpp" #include "Print.hpp" #include "SupportMaterial.hpp" @@ -445,8 +444,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t Polygons collect_slices_outer(const Layer &layer) { Polygons out; - out.reserve(out.size() + layer.slices.size()); - for (const ExPolygon &expoly : layer.slices) + out.reserve(out.size() + layer.lslices.size()); + for (const ExPolygon &expoly : layer.lslices) out.emplace_back(expoly.contour); return out; } @@ -907,9 +906,9 @@ namespace SupportMaterialInternal { polyline.extend_start(fw); polyline.extend_end(fw); // Is the straight perimeter segment supported at both sides? - for (size_t i = 0; i < lower_layer.slices.size(); ++ i) - if (lower_layer.slices_bboxes[i].contains(polyline.first_point()) && lower_layer.slices_bboxes[i].contains(polyline.last_point()) && - lower_layer.slices[i].contains(polyline.first_point()) && lower_layer.slices[i].contains(polyline.last_point())) { + for (size_t i = 0; i < lower_layer.lslices.size(); ++ i) + if (lower_layer.lslices_bboxes[i].contains(polyline.first_point()) && lower_layer.lslices_bboxes[i].contains(polyline.last_point()) && + lower_layer.lslices[i].contains(polyline.first_point()) && lower_layer.lslices[i].contains(polyline.last_point())) { // Offset a polyline into a thick line. polygons_append(bridges, offset(polyline, 0.5f * w + 10.f)); break; @@ -998,7 +997,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // inflate the polygons over and over. Polygons &covered = buildplate_covered[layer_id]; covered = buildplate_covered[layer_id - 1]; - polygons_append(covered, offset(lower_layer.slices, scale_(0.01))); + polygons_append(covered, offset(lower_layer.lslices, scale_(0.01))); covered = union_(covered, false); // don't apply the safety offset. } } @@ -1027,7 +1026,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ Polygons contact_polygons; Polygons slices_margin_cached; float slices_margin_cached_offset = -1.; - Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id-1]->slices); + Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id-1]->lslices); // Offset of the lower layer, to trim the support polygons with to calculate dense supports. float no_interface_offset = 0.f; if (layer_id == 0) { @@ -1166,7 +1165,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ slices_margin_cached_offset = slices_margin_offset; slices_margin_cached = (slices_margin_offset == 0.f) ? lower_layer_polygons : - offset2(to_polygons(lower_layer.slices), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); + offset2(to_polygons(lower_layer.lslices), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); if (! buildplate_covered.empty()) { // Trim the inflated contact surfaces by the top surfaces as well. polygons_append(slices_margin_cached, buildplate_covered[layer_id]); @@ -1573,7 +1572,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta task_group.run([this, &projection, &projection_raw, &layer, &layer_support_area, layer_id] { // Remove the areas that touched from the projection that will continue on next, lower, top surfaces. // Polygons trimming = union_(to_polygons(layer.slices), touching, true); - Polygons trimming = offset(layer.slices, float(SCALED_EPSILON)); + Polygons trimming = offset(layer.lslices, float(SCALED_EPSILON)); projection = diff(projection_raw, trimming, false); #ifdef SLIC3R_DEBUG { @@ -2105,7 +2104,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( const Layer &object_layer = *object.layers()[i]; if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON) break; - polygons_append(polygons_trimming, offset(object_layer.slices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); + polygons_append(polygons_trimming, offset(object_layer.lslices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); } if (! m_slicing_params.soluble_interface) { // Collect all bottom surfaces, which will be extruded with a bridging flow. @@ -2218,7 +2217,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf // Expand the bases of the support columns in the 1st layer. columns_base->polygons = diff( offset(columns_base->polygons, inflate_factor_1st_layer), - offset(m_object->layers().front()->slices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS)); + offset(m_object->layers().front()->lslices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (contacts != nullptr) columns_base->polygons = diff(columns_base->polygons, interface_polygons); } From 83cbe1dd3307f1698d4643edf9f9e2af214fac36 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 3 Jan 2020 14:42:52 +0100 Subject: [PATCH 150/162] 3DConnexion devices' Y axis used for zoom in/zoom out --- src/libslic3r/Technologies.hpp | 9 +++++ src/slic3r/GUI/AppConfig.cpp | 24 +++++++++++++ src/slic3r/GUI/AppConfig.hpp | 11 ++++-- src/slic3r/GUI/Mouse3DController.cpp | 50 ++++++++++++++++++++++++---- src/slic3r/GUI/Mouse3DController.hpp | 11 ++++++ 5 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3d1234cbfc..64c5ce953d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -59,4 +59,13 @@ // Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member #define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1) + +//================== +// 2.2.0.beta1 techs +//================== +#define ENABLE_2_2_0_BETA1 1 + +// Enable using Y axis of 3Dconnexion devices as zoom +#define ENABLE_3DCONNEXION_Y_AS_ZOOM (1 && ENABLE_2_2_0_BETA1) + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 7055822513..eb0a7fca69 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -271,7 +271,11 @@ void AppConfig::set_recent_projects(const std::vector& recent_proje } } +#if ENABLE_3DCONNEXION_Y_AS_ZOOM +void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed) +#else void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone) +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM { std::string key = std::string("mouse_device:") + name; auto it = m_storage.find(key); @@ -283,6 +287,9 @@ void AppConfig::set_mouse_device(const std::string& name, double translation_spe it->second["translation_deadzone"] = std::to_string(translation_deadzone); it->second["rotation_speed"] = std::to_string(rotation_speed); it->second["rotation_deadzone"] = std::to_string(rotation_deadzone); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + it->second["zoom_speed"] = std::to_string(zoom_speed); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM } bool AppConfig::get_mouse_device_translation_speed(const std::string& name, double& speed) @@ -345,6 +352,23 @@ bool AppConfig::get_mouse_device_rotation_deadzone(const std::string& name, floa return true; } +#if ENABLE_3DCONNEXION_Y_AS_ZOOM +bool AppConfig::get_mouse_device_zoom_speed(const std::string& name, double& speed) +{ + std::string key = std::string("mouse_device:") + name; + auto it = m_storage.find(key); + if (it == m_storage.end()) + return false; + + auto it_val = it->second.find("zoom_speed"); + if (it_val == it->second.end()) + return false; + + speed = (float)::atof(it_val->second.c_str()); + return true; +} +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM + void AppConfig::update_config_dir(const std::string &dir) { this->set("recent", "config_directory", dir); diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 3553704506..b432367b66 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -131,11 +131,18 @@ public: std::vector get_recent_projects() const; void set_recent_projects(const std::vector& recent_projects); - void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone); - bool get_mouse_device_translation_speed(const std::string& name, double& speed); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed); +#else + void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM + bool get_mouse_device_translation_speed(const std::string& name, double& speed); bool get_mouse_device_translation_deadzone(const std::string& name, double& deadzone); bool get_mouse_device_rotation_speed(const std::string& name, float& speed); bool get_mouse_device_rotation_deadzone(const std::string& name, float& deadzone); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + bool get_mouse_device_zoom_speed(const std::string& name, double& speed); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM 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 e91b6175f8..707a1d143a 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -57,13 +57,19 @@ const double Mouse3DController::State::DefaultTranslationScale = 2.5; const double Mouse3DController::State::MaxTranslationDeadzone = 0.2; const double Mouse3DController::State::DefaultTranslationDeadzone = 0.5 * Mouse3DController::State::MaxTranslationDeadzone; const float Mouse3DController::State::DefaultRotationScale = 1.0f; -const float Mouse3DController::State::MaxRotationDeadzone = (float)Mouse3DController::State::MaxTranslationDeadzone; +const float Mouse3DController::State::MaxRotationDeadzone = 0.2f; const float Mouse3DController::State::DefaultRotationDeadzone = 0.5f * Mouse3DController::State::MaxRotationDeadzone; +#if ENABLE_3DCONNEXION_Y_AS_ZOOM +const double Mouse3DController::State::DefaultZoomScale = 0.1; +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM Mouse3DController::State::State() : m_buttons_enabled(false) , m_translation_params(DefaultTranslationScale, DefaultTranslationDeadzone) , m_rotation_params(DefaultRotationScale, DefaultRotationDeadzone) +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + , m_zoom_params(DefaultZoomScale, 0.0) +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM , m_mouse_wheel_counter(0) #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT , m_translation_queue_max_size(0) @@ -149,7 +155,13 @@ bool Mouse3DController::State::apply(Camera& camera) if (has_translation()) { const Vec3d& translation = m_translation.queue.front(); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + camera.set_target(camera.get_target() + m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); + if (translation(1) != 0.0) + camera.update_zoom(m_zoom_params.scale * translation(1) / std::abs(translation(1))); +#else camera.set_target(camera.get_target() + m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(1) * camera.get_dir_forward() + translation(2) * camera.get_dir_up())); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM m_translation.queue.pop(); ret = true; } @@ -309,20 +321,30 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign ImGui::PopStyleColor(); float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale; - if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 5.0f, "%.1f")) + if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.2f, 5.0f, "%.1f")) m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale); float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale; - if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 5.0f, "%.1f")) + if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.2f, 5.0f, "%.1f")) m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + float zoom_scale = m_state.get_zoom_scale() / State::DefaultZoomScale; + if (imgui.slider_float(_(L("Zoom")), &zoom_scale, 0.2f, 5.0f, "%.1f")) + m_state.set_zoom_scale(State::DefaultZoomScale * zoom_scale); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM + ImGui::Separator(); ImGui::PushStyleColor(ImGuiCol_Text, color); imgui.text(_(L("Deadzone:"))); ImGui::PopStyleColor(); float translation_deadzone = (float)m_state.get_translation_deadzone(); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + if (imgui.slider_float(_(L("Translation")) + "/" + _(L("Zoom")), &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f")) +#else if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f")) +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM m_state.set_translation_deadzone((double)translation_deadzone); float rotation_deadzone = m_state.get_rotation_deadzone(); @@ -629,15 +651,24 @@ bool Mouse3DController::connect_device() float rotation_speed = 1.0; double translation_deadzone = State::DefaultTranslationDeadzone; float rotation_deadzone = State::DefaultRotationDeadzone; +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + double zoom_speed = 1.0; +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM wxGetApp().app_config->get_mouse_device_translation_speed(m_device_str, translation_speed); wxGetApp().app_config->get_mouse_device_translation_deadzone(m_device_str, translation_deadzone); wxGetApp().app_config->get_mouse_device_rotation_speed(m_device_str, rotation_speed); wxGetApp().app_config->get_mouse_device_rotation_deadzone(m_device_str, rotation_deadzone); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + wxGetApp().app_config->get_mouse_device_zoom_speed(m_device_str, zoom_speed); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM // clamp to valid values - m_state.set_translation_scale(State::DefaultTranslationScale * std::max(0.5, std::min(2.0, translation_speed))); - m_state.set_translation_deadzone(std::max(0.0, std::min(State::MaxTranslationDeadzone, translation_deadzone))); - m_state.set_rotation_scale(State::DefaultRotationScale * std::max(0.5f, std::min(2.0f, rotation_speed))); - m_state.set_rotation_deadzone(std::max(0.0f, std::min(State::MaxRotationDeadzone, rotation_deadzone))); + m_state.set_translation_scale(State::DefaultTranslationScale * std::clamp(translation_speed, 0.2, 5.0)); + m_state.set_translation_deadzone(std::clamp(translation_deadzone, 0.0, State::MaxTranslationDeadzone)); + m_state.set_rotation_scale(State::DefaultRotationScale * std::clamp(rotation_speed, 0.2f, 5.0f)); + m_state.set_rotation_deadzone(std::clamp(rotation_deadzone, 0.0f, State::MaxRotationDeadzone)); +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + m_state.set_zoom_scale(State::DefaultZoomScale * std::clamp(zoom_speed, 0.2, 5.0)); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM } #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT else @@ -663,8 +694,13 @@ void Mouse3DController::disconnect_device() m_thread.join(); // Store current device parameters into the config +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + wxGetApp().app_config->set_mouse_device(m_device_str, m_state.get_translation_scale() / State::DefaultTranslationScale, m_state.get_translation_deadzone(), + m_state.get_rotation_scale() / State::DefaultRotationScale, m_state.get_rotation_deadzone(), m_state.get_zoom_scale() / State::DefaultZoomScale); +#else wxGetApp().app_config->set_mouse_device(m_device_str, m_state.get_translation_scale() / State::DefaultTranslationScale, m_state.get_translation_deadzone(), m_state.get_rotation_scale() / State::DefaultRotationScale, m_state.get_rotation_deadzone()); +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM wxGetApp().app_config->save(); // Close the 3Dconnexion device diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index 9e5161ee7d..3598d7df7a 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -33,6 +33,9 @@ class Mouse3DController static const float DefaultRotationScale; static const float MaxRotationDeadzone; static const float DefaultRotationDeadzone; +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + static const double DefaultZoomScale; +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM private: template @@ -64,6 +67,9 @@ class Mouse3DController CustomParameters m_translation_params; CustomParameters m_rotation_params; +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + CustomParameters m_zoom_params; +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM // When the 3Dconnexion driver is running the system gets, by default, mouse wheel events when rotations around the X axis are detected. // We want to filter these out because we are getting the data directly from the device, bypassing the driver, and those mouse wheel events interfere @@ -99,6 +105,11 @@ class Mouse3DController float get_rotation_scale() const { return m_rotation_params.scale; } void set_rotation_scale(float scale) { m_rotation_params.scale = scale; } +#if ENABLE_3DCONNEXION_Y_AS_ZOOM + double get_zoom_scale() const { return m_zoom_params.scale; } + void set_zoom_scale(double scale) { m_zoom_params.scale = scale; } +#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM + double get_translation_deadzone() const { return m_translation_params.deadzone; } void set_translation_deadzone(double deadzone) { m_translation_params.deadzone = deadzone; } From 30f7a2b8e5b369319ada02455d5fec7633c46b8b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 3 Jan 2020 16:09:16 +0100 Subject: [PATCH 151/162] Fix of #3382 --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0505d748ed..271e51bc24 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2930,6 +2930,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t la layer_height <= get_max_layer_height(extruder_idx)) { config->set_key_value("layer_height", new ConfigOptionFloat(layer_height)); + changed_object(obj_idx); return true; } @@ -2951,6 +2952,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay ranges.erase(range); ranges[new_range] = config; + changed_object(obj_idx); wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx)); // To avoid update selection after deleting of a selected item (under GTK) From 9406b5044753cff3ed20ec28f6c5b6067e6fd5a3 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 3 Jan 2020 16:32:56 +0100 Subject: [PATCH 152/162] Const correctness improvements: removed some unnecessary const_casts that remove const. --- src/PrusaSlicer.cpp | 2 +- src/avrdude/avrdude-slic3r.cpp | 6 ++-- src/libslic3r/Config.cpp | 35 ++++++++++++------------ src/libslic3r/Config.hpp | 2 +- src/libslic3r/Format/AMF.cpp | 8 +++--- src/libslic3r/Format/objparser.cpp | 4 +-- src/libslic3r/Semver.hpp | 2 +- src/libslic3r/utils.cpp | 4 +-- src/slic3r/Config/Version.cpp | 2 +- src/slic3r/GUI/Camera.cpp | 2 +- src/slic3r/GUI/GLShader.cpp | 4 +-- src/slic3r/GUI/PresetBundle.cpp | 8 ++++-- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 13 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index f708679c18..d755f0b2e7 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -691,7 +691,7 @@ extern "C" { for (size_t i = 0; i < argc; ++ i) argv_narrow.emplace_back(boost::nowide::narrow(argv[i])); for (size_t i = 0; i < argc; ++ i) - argv_ptrs[i] = const_cast(argv_narrow[i].data()); + argv_ptrs[i] = argv_narrow[i].data(); // Call the UTF8 main. return CLI().run(argc, argv_ptrs.data()); } diff --git a/src/avrdude/avrdude-slic3r.cpp b/src/avrdude/avrdude-slic3r.cpp index b561cd8433..6dbb842265 100644 --- a/src/avrdude/avrdude-slic3r.cpp +++ b/src/avrdude/avrdude-slic3r.cpp @@ -93,11 +93,11 @@ void AvrDude::priv::unset_handlers() int AvrDude::priv::run_one(const std::vector &args) { - std::vector c_args { const_cast(PACKAGE) }; + std::vector c_args { PACKAGE }; std::string command_line { PACKAGE }; for (const auto &arg : args) { - c_args.push_back(const_cast(arg.data())); + c_args.push_back(arg.c_str()); command_line.push_back(' '); command_line.append(arg); } @@ -107,7 +107,7 @@ int AvrDude::priv::run_one(const std::vector &args) { message_fn(command_line.c_str(), (unsigned)command_line.size()); - const auto res = ::avrdude_main(static_cast(c_args.size()), c_args.data()); + const auto res = ::avrdude_main(static_cast(c_args.size()), const_cast(c_args.data())); return res; } diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index a81e9521af..bcd0172780 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -630,39 +630,38 @@ size_t ConfigBase::load_from_gcode_string(const char* str) return 0; // Walk line by line in reverse until a non-configuration key appears. - char *data_start = const_cast(str); + const char *data_start = str; // boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved. - char *end = data_start + strlen(str); + const char *end = data_start + strlen(str); size_t num_key_value_pairs = 0; for (;;) { // Extract next line. for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end); if (end == data_start) break; - char *start = end; - *(++end) = 0; + const char *start = end ++; for (; start > data_start && *start != '\r' && *start != '\n'; --start); if (start == data_start) break; // Extracted a line from start to end. Extract the key = value pair. - if (end - (++start) < 10 || start[0] != ';' || start[1] != ' ') + if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ') break; - char *key = start + 2; + const char *key = start + 2; if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z')) // A key must start with a letter. break; - char *sep = strchr(key, '='); - if (sep == nullptr || sep[-1] != ' ' || sep[1] != ' ') + const char *sep = key; + for (; sep != end && *sep != '='; ++ sep) ; + if (sep == end || sep[-1] != ' ' || sep[1] != ' ') break; - char *value = sep + 2; + const char *value = sep + 2; if (value > end) break; - char *key_end = sep - 1; + const char *key_end = sep - 1; if (key_end - key < 3) break; - *key_end = 0; // The key may contain letters, digits and underscores. - for (char *c = key; c != key_end; ++c) + for (const char *c = key; c != key_end; ++ c) if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) { key = nullptr; break; @@ -670,7 +669,7 @@ size_t ConfigBase::load_from_gcode_string(const char* str) if (key == nullptr) break; try { - this->set_deserialize(key, value); + this->set_deserialize(std::string(key, key_end), std::string(value, end)); ++num_key_value_pairs; } catch (UnknownOptionException & /* e */) { @@ -760,15 +759,15 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre void DynamicConfig::read_cli(const std::vector &tokens, t_config_option_keys* extra, t_config_option_keys* keys) { - std::vector args; + std::vector args; // push a bogus executable name (argv[0]) - args.emplace_back(const_cast("")); + args.emplace_back(""); for (size_t i = 0; i < tokens.size(); ++ i) - args.emplace_back(const_cast(tokens[i].c_str())); - this->read_cli(int(args.size()), &args[0], extra, keys); + args.emplace_back(tokens[i].c_str()); + this->read_cli(int(args.size()), args.data(), extra, keys); } -bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys) +bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys) { // cache the CLI option => opt_key mapping std::map opts; diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index c49dd134ed..87a79d93f5 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1779,7 +1779,7 @@ public: // Command line processing void read_cli(const std::vector &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr); - bool read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys = nullptr); + bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr); std::map>::const_iterator cbegin() const { return options.cbegin(); } std::map>::const_iterator cend() const { return options.cend(); } diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 847ac6f5c3..5b65d8fa2d 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -683,7 +683,7 @@ void AMFParserContext::endElement(const char * /* name */) config->set_deserialize(opt_key, m_value[1]); } else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) { // Parse object's layer height profile, a semicolon separated list of floats. - char *p = const_cast(m_value[1].c_str()); + char *p = m_value[1].data(); for (;;) { char *end = strchr(p, ';'); if (end != nullptr) @@ -698,7 +698,7 @@ void AMFParserContext::endElement(const char * /* name */) // Parse object's layer height profile, a semicolon separated list of floats. unsigned char coord_idx = 0; Eigen::Matrix point(Eigen::Matrix::Zero()); - char *p = const_cast(m_value[1].c_str()); + char *p = m_value[1].data(); for (;;) { char *end = strchr(p, ';'); if (end != nullptr) @@ -718,7 +718,7 @@ void AMFParserContext::endElement(const char * /* name */) else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE && m_object && strcmp(opt_key, "layer_height_range") == 0) { // Parse object's layer_height_range, a semicolon separated doubles. - char* p = const_cast(m_value[1].c_str()); + char* p = m_value[1].data(); char* end = strchr(p, ';'); *end = 0; @@ -1010,7 +1010,7 @@ bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool c return false; std::string zip_mask(2, '\0'); - file.read(const_cast(zip_mask.data()), 2); + file.read(zip_mask.data(), 2); file.close(); return (zip_mask == "PK") ? load_amf_archive(path, config, model, check_version) : load_amf_file(path, config, model); diff --git a/src/libslic3r/Format/objparser.cpp b/src/libslic3r/Format/objparser.cpp index c805667f81..28f2fdbbd5 100644 --- a/src/libslic3r/Format/objparser.cpp +++ b/src/libslic3r/Format/objparser.cpp @@ -420,7 +420,7 @@ bool loadvector(FILE *pFile, std::vector &v) if (::fread(&len, sizeof(len), 1, pFile) != 1) return false; std::string s(" ", len); - if (::fread(const_cast(s.c_str()), 1, len, pFile) != len) + if (::fread(s.data(), 1, len, pFile) != len) return false; v.push_back(std::move(s)); } @@ -442,7 +442,7 @@ bool loadvectornameidx(FILE *pFile, std::vector &v) if (::fread(&len, sizeof(len), 1, pFile) != 1) return false; v[i].name.assign(" ", len); - if (::fread(const_cast(v[i].name.c_str()), 1, len, pFile) != len) + if (::fread(v[i].name.data(), 1, len, pFile) != len) return false; } return true; diff --git a/src/libslic3r/Semver.hpp b/src/libslic3r/Semver.hpp index 1723910773..24ca74f837 100644 --- a/src/libslic3r/Semver.hpp +++ b/src/libslic3r/Semver.hpp @@ -149,7 +149,7 @@ private: Semver(semver_t ver) : ver(ver) {} static semver_t semver_zero() { return { 0, 0, 0, nullptr, nullptr }; } - static char * strdup(const std::string &str) { return ::semver_strdup(const_cast(str.c_str())); } + static char * strdup(const std::string &str) { return ::semver_strdup(str.data()); } }; diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index b7155ddc84..36653cdaff 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -535,7 +535,7 @@ std::string encode_path(const char *src) // Convert a wide string to a local code page. int size_needed = ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), nullptr, 0, nullptr, nullptr); std::string str_dst(size_needed, 0); - ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), const_cast(str_dst.data()), size_needed, nullptr, nullptr); + ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), str_dst.data(), size_needed, nullptr, nullptr); return str_dst; #else /* WIN32 */ return src; @@ -552,7 +552,7 @@ std::string decode_path(const char *src) // Convert the string encoded using the local code page to a wide string. int size_needed = ::MultiByteToWideChar(0, 0, src, len, nullptr, 0); std::wstring wstr_dst(size_needed, 0); - ::MultiByteToWideChar(0, 0, src, len, const_cast(wstr_dst.data()), size_needed); + ::MultiByteToWideChar(0, 0, src, len, wstr_dst.data(), size_needed); // Convert a wide string to utf8. return boost::nowide::narrow(wstr_dst.c_str()); #else /* WIN32 */ diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index fcebf88d14..2104a6eeab 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -205,7 +205,7 @@ size_t Index::load(const boost::filesystem::path &path) #endif ++ idx_line; // Skip the initial white spaces. - char *key = left_trim(const_cast(line.data())); + char *key = left_trim(line.data()); if (*key == '#') // Skip a comment line. continue; diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index bb514e8888..fa7a3be21e 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -338,7 +338,7 @@ void Camera::debug_render() const float fov = (float)get_fov(); float gui_scale = (float)get_gui_scale(); - ImGui::InputText("Type", const_cast(type.data()), type.length(), ImGuiInputTextFlags_ReadOnly); + ImGui::InputText("Type", type.data(), type.length(), ImGuiInputTextFlags_ReadOnly); ImGui::Separator(); ImGui::InputFloat3("Position", position.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat3("Target", target.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 11f109fd5f..c310760603 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -142,7 +142,7 @@ bool GLShader::load_from_file(const char* fragment_shader_filename, const char* int file_length = (int)vs.tellg(); vs.seekg(0, vs.beg); std::string vertex_shader(file_length, '\0'); - vs.read(const_cast(vertex_shader.data()), file_length); + vs.read(vertex_shader.data(), file_length); if (!vs.good()) return false; @@ -156,7 +156,7 @@ bool GLShader::load_from_file(const char* fragment_shader_filename, const char* file_length = (int)fs.tellg(); fs.seekg(0, fs.beg); std::string fragment_shader(file_length, '\0'); - fs.read(const_cast(fragment_shader.data()), file_length); + fs.read(fragment_shader.data(), file_length); if (!fs.good()) return false; diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 3ede7a4e06..219d7b89da 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -560,9 +560,11 @@ DynamicPrintConfig PresetBundle::full_fff_config() const while (filament_configs.size() < num_extruders) filament_configs.emplace_back(&this->filaments.first_visible().config); for (const DynamicPrintConfig *cfg : filament_configs) { - compatible_printers_condition.emplace_back(Preset::compatible_printers_condition(*const_cast(cfg))); - compatible_prints_condition .emplace_back(Preset::compatible_prints_condition(*const_cast(cfg))); - inherits .emplace_back(Preset::inherits(*const_cast(cfg))); + // The compatible_prints/printers_condition() returns a reference to configuration key, which may not yet exist. + DynamicPrintConfig &cfg_rw = *const_cast(cfg); + compatible_printers_condition.emplace_back(Preset::compatible_printers_condition(cfg_rw)); + compatible_prints_condition .emplace_back(Preset::compatible_prints_condition(cfg_rw)); + inherits .emplace_back(Preset::inherits(cfg_rw)); } // Option values to set a ConfigOptionVector from. std::vector filament_opts(num_extruders, nullptr); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 353337e473..9ef31748de 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -325,7 +325,7 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str { if(pw->pw_name == username) { - std::string name = basename(const_cast(path.c_str())); + std::string name = basename(path.data()); m_current_drives.push_back(DriveData(name,path)); } } From 5294c85dfcf0092483c7179cbfd3bbe2b6a77732 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 6 Jan 2020 09:32:13 +0100 Subject: [PATCH 153/162] Some minor polishing of Color print back end. --- src/libslic3r/GCode.hpp | 11 +++++------ src/libslic3r/Model.cpp | 22 ++++++++++------------ src/libslic3r/Model.hpp | 26 ++++++++++---------------- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 68bb85a988..497dc8c718 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -362,12 +362,11 @@ protected: bool m_second_layer_things_done; // Index of a last object copy extruded. std::pair m_last_obj_copy; - /* Extensions for colorprint - now it's not a just color_print_heights, - * there can be some custom gcode. - * Updated before the export and erased during the process, - * so no toolchange occurs twice. - * */ - std::vector m_custom_gcode_per_print_z; + // Extensions for colorprint - now it's not a just color_print_heights, + // there can be some custom gcode. + // Updated before the export and erased during the process, + // so no toolchange occurs twice. + std::vector m_custom_gcode_per_print_z; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 5167337086..96a32680e6 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -66,7 +66,7 @@ Model& Model::assign_copy(Model &&rhs) rhs.objects.clear(); // copy custom code per height - this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z; + this->custom_gcode_per_print_z = std::move(rhs.custom_gcode_per_print_z); return *this; } @@ -1946,25 +1946,23 @@ extern bool model_has_advanced_features(const Model &model) extern void update_custom_gcode_per_print_z_from_config(std::vector& custom_gcode_per_print_z, DynamicPrintConfig* config) { - if (!config->has("colorprint_heights")) + auto *colorprint_heights = config->option("colorprint_heights"); + if (colorprint_heights == nullptr) return; - const std::vector& colors = GCodePreviewData::ColorPrintColors(); - - const auto& colorprint_values = config->option("colorprint_heights")->values; - - if (!colorprint_values.empty()) - { + if (custom_gcode_per_print_z.empty() && ! colorprint_heights->values.empty()) { + // Convert the old colorprint_heighs only if there is no equivalent data in a new format. + const std::vector& colors = GCodePreviewData::ColorPrintColors(); + const auto& colorprint_values = colorprint_heights->values; custom_gcode_per_print_z.clear(); custom_gcode_per_print_z.reserve(colorprint_values.size()); int i = 0; for (auto val : colorprint_values) custom_gcode_per_print_z.emplace_back(Model::CustomGCode{ val, ColorChangeCode, 1, colors[(++i)%7] }); - } + } - /* There is one and only place this configuration option is used now. - * It wouldn't be used in the future, so erase it. - * */ + // The "colorprint_heights" config value has been deprecated. At this point of time it has been converted + // to a new format and therefore it shall be erased. config->erase("colorprint_heights"); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index c5a992e49d..44f5049c9f 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -755,21 +755,15 @@ public: // Extensions for color print struct CustomGCode { - bool operator<(const CustomGCode& other) const { return other.print_z > this->print_z; } - bool operator==(const CustomGCode& other) const + bool operator<(const CustomGCode& rhs) const { return this->print_z < rhs.print_z; } + bool operator==(const CustomGCode& rhs) const { - return (other.print_z == this->print_z ) && - (other.gcode == this->gcode ) && - (other.extruder == this->extruder ) && - (other.color == this->color ); - } - bool operator!=(const CustomGCode& other) const - { - return (other.print_z != this->print_z ) || - (other.gcode != this->gcode ) || - (other.extruder != this->extruder ) || - (other.color != this->color ); + return (rhs.print_z == this->print_z ) && + (rhs.gcode == this->gcode ) && + (rhs.extruder == this->extruder ) && + (rhs.color == this->color ); } + bool operator!=(const CustomGCode& rhs) const { return ! (*this == rhs); } double print_z; std::string gcode; @@ -880,9 +874,9 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const extern bool model_has_multi_part_objects(const Model &model); // If the model has advanced features, then it cannot be processed in simple mode. extern bool model_has_advanced_features(const Model &model); -/* If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer), - * then model.custom_gcode_per_print_z should be updated considering this option - * */ +// If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer), +// and if model.custom_gcode_per_print_z is empty (there is no color print data available in a new format +// then model.custom_gcode_per_print_z should be updated considering this option. extern void update_custom_gcode_per_print_z_from_config(std::vector& custom_gcode_per_print_z, DynamicPrintConfig* config); #ifndef NDEBUG From afbc4a4cf2e71d11885f9a7d449df3deaa4eaf2b Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 6 Jan 2020 09:36:03 +0100 Subject: [PATCH 154/162] Fixing perl bindings after refactoring --- xs/xsp/Layer.xsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 6f3164707a..6ca953f82c 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -61,7 +61,7 @@ Ref add_region(PrintRegion* print_region); ExPolygonCollection* slices() - %code%{ RETVAL = new ExPolygonCollection(THIS->slices); %}; + %code%{ RETVAL = new ExPolygonCollection(THIS->lslices); %}; int ptr() %code%{ RETVAL = (int)(intptr_t)THIS; %}; @@ -110,7 +110,7 @@ Ref add_region(PrintRegion* print_region); ExPolygonCollection* slices() - %code%{ RETVAL = new ExPolygonCollection(THIS->slices); %}; + %code%{ RETVAL = new ExPolygonCollection(THIS->lslices); %}; void export_region_slices_to_svg(const char *path); void export_region_fill_surfaces_to_svg(const char *path); From e7b835dc523df5c2cf1981f6e93aa9ad4b463f9b Mon Sep 17 00:00:00 2001 From: Spencer Owen Date: Sat, 28 Dec 2019 10:41:48 -0700 Subject: [PATCH 155/162] Add Astrobox to Print Host options --- resources/localization/list.txt | 1 + src/libslic3r/PrintConfig.cpp | 2 + src/libslic3r/PrintConfig.hpp | 3 +- src/slic3r/CMakeLists.txt | 2 + src/slic3r/Utils/AstroBox.cpp | 215 ++++++++++++++++++++++++++++++++ src/slic3r/Utils/AstroBox.hpp | 65 ++++++++++ src/slic3r/Utils/PrintHost.cpp | 2 + 7 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 src/slic3r/Utils/AstroBox.cpp create mode 100644 src/slic3r/Utils/AstroBox.hpp diff --git a/resources/localization/list.txt b/resources/localization/list.txt index 7f0b672526..93ee2f441d 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -50,6 +50,7 @@ src/slic3r/GUI/ExtruderSequenceDialog.cpp src/slic3r/Utils/Duet.cpp src/slic3r/Utils/OctoPrint.cpp src/slic3r/Utils/FlashAir.cpp +src/slic3r/Utils/AstroBox.cpp src/slic3r/Utils/PresetUpdater.cpp src/slic3r/Utils/FixModelByWin10.cpp src/libslic3r/SLA/SLAPad.cpp diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 82815131e2..0835693b2e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1333,9 +1333,11 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("octoprint"); def->enum_values.push_back("duet"); def->enum_values.push_back("flashair"); + def->enum_values.push_back("astrobox"); def->enum_labels.push_back("OctoPrint"); def->enum_labels.push_back("Duet"); def->enum_labels.push_back("FlashAir"); + def->enum_values.push_back("AstroBox"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(htOctoPrint)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 5f5a861da3..6d70f54082 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -30,7 +30,7 @@ enum GCodeFlavor : unsigned char { }; enum PrintHostType { - htOctoPrint, htDuet, htFlashAir + htOctoPrint, htDuet, htFlashAir, htAstroBox }; enum InfillPattern { @@ -103,6 +103,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum::g keys_map["octoprint"] = htOctoPrint; keys_map["duet"] = htDuet; keys_map["flashair"] = htFlashAir; + keys_map["astrobox"] = htAstroBox; } return keys_map; } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5b55b96b4b..9fd8462727 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -152,6 +152,8 @@ set(SLIC3R_GUI_SOURCES Utils/Duet.hpp Utils/FlashAir.cpp Utils/FlashAir.hpp + Utils/AstroBox.cpp + Utils/AstroBox.hpp Utils/PrintHost.cpp Utils/PrintHost.hpp Utils/Bonjour.cpp diff --git a/src/slic3r/Utils/AstroBox.cpp b/src/slic3r/Utils/AstroBox.cpp new file mode 100644 index 0000000000..ded03ed4ce --- /dev/null +++ b/src/slic3r/Utils/AstroBox.cpp @@ -0,0 +1,215 @@ +#include "AstroBox.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libslic3r/PrintConfig.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "Http.hpp" + + +namespace fs = boost::filesystem; +namespace pt = boost::property_tree; + + +namespace Slic3r { + +AstroBox::AstroBox(DynamicPrintConfig *config) : + host(config->opt_string("print_host")), + apikey(config->opt_string("printhost_apikey")), + cafile(config->opt_string("printhost_cafile")) +{} + +AstroBox::~AstroBox() {} + +const char* AstroBox::get_name() const { return "AstroBox"; } + +bool AstroBox::test(wxString &msg) const +{ + // Since the request is performed synchronously here, + // it is ok to refer to `msg` from within the closure + + const char *name = get_name(); + + bool res = true; + auto url = make_url("api/version"); + + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url; + + auto http = Http::get(std::move(url)); + set_auth(http); + http.on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; + res = false; + msg = format_error(body, error, status); + }) + .on_complete([&, this](std::string body, unsigned) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got version: %2%") % name % body; + + try { + std::stringstream ss(body); + pt::ptree ptree; + pt::read_json(ss, ptree); + + if (! ptree.get_optional("api")) { + res = false; + return; + } + + const auto text = ptree.get_optional("text"); + res = validate_version_text(text); + if (! res) { + msg = wxString::Format(_(L("Mismatched type of print host: %s")), text ? *text : "AstroBox"); + } + } + catch (const std::exception &) { + res = false; + msg = "Could not parse server response"; + } + }) + .perform_sync(); + + return res; +} + +wxString AstroBox::get_test_ok_msg () const +{ + return _(L("Connection to AstroBox works correctly.")); +} + +wxString AstroBox::get_test_failed_msg (wxString &msg) const +{ + return wxString::Format("%s: %s\n\n%s", + _(L("Could not connect to AstroBox")), msg, _(L("Note: AstroBox version at least 1.1.0 is required."))); +} + +bool AstroBox::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const +{ + const char *name = get_name(); + + const auto upload_filename = upload_data.upload_path.filename(); + const auto upload_parent_path = upload_data.upload_path.parent_path(); + + wxString test_msg; + if (! test(test_msg)) { + error_fn(std::move(test_msg)); + return false; + } + + bool res = true; + + auto url = make_url("api/files/local"); + + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%") + % name + % upload_data.source_path + % url + % upload_filename.string() + % upload_parent_path.string() + % upload_data.start_print; + + auto http = Http::post(std::move(url)); + set_auth(http); + http.form_add("print", upload_data.start_print ? "true" : "false") + .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? + .form_add_file("file", upload_data.source_path.string(), upload_filename.string()) + .on_complete([&](std::string body, unsigned status) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: File uploaded: HTTP %2%: %3%") % name % status % body; + }) + .on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error uploading file: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; + error_fn(format_error(body, error, status)); + res = false; + }) + .on_progress([&](Http::Progress progress, bool &cancel) { + prorgess_fn(std::move(progress), cancel); + if (cancel) { + // Upload was canceled + BOOST_LOG_TRIVIAL(info) << "AstroBox: Upload canceled"; + res = false; + } + }) + .perform_sync(); + + return res; +} + +bool AstroBox::has_auto_discovery() const +{ + return true; +} + +bool AstroBox::can_test() const +{ + return true; +} + +bool AstroBox::can_start_print() const +{ + return true; +} + +bool AstroBox::validate_version_text(const boost::optional &version_text) const +{ + return version_text ? boost::starts_with(*version_text, "AstroBox") : true; +} + +void AstroBox::set_auth(Http &http) const +{ + http.header("X-Api-Key", apikey); + + if (! cafile.empty()) { + http.ca_file(cafile); + } +} + +std::string AstroBox::make_url(const std::string &path) const +{ + if (host.find("http://") == 0 || host.find("https://") == 0) { + if (host.back() == '/') { + return (boost::format("%1%%2%") % host % path).str(); + } else { + return (boost::format("%1%/%2%") % host % path).str(); + } + } else { + return (boost::format("http://%1%/%2%") % host % path).str(); + } +} + + +// SL1Host + +SL1Host::~SL1Host() {} + +const char* SL1Host::get_name() const { return "SL1Host"; } + +wxString SL1Host::get_test_ok_msg () const +{ + return _(L("Connection to Prusa SL1 works correctly.")); +} + +wxString SL1Host::get_test_failed_msg (wxString &msg) const +{ + return wxString::Format("%s: %s", _(L("Could not connect to Prusa SLA")), msg); +} + +bool SL1Host::can_start_print() const +{ + return false; +} + +bool SL1Host::validate_version_text(const boost::optional &version_text) const +{ + return version_text ? boost::starts_with(*version_text, "Prusa SLA") : false; +} + + +} diff --git a/src/slic3r/Utils/AstroBox.hpp b/src/slic3r/Utils/AstroBox.hpp new file mode 100644 index 0000000000..1474132da6 --- /dev/null +++ b/src/slic3r/Utils/AstroBox.hpp @@ -0,0 +1,65 @@ +#ifndef slic3r_AstroBox_hpp_ +#define slic3r_AstroBox_hpp_ + +#include +#include +#include + +#include "PrintHost.hpp" + + +namespace Slic3r { + + +class DynamicPrintConfig; +class Http; + +class AstroBox : public PrintHost +{ +public: + AstroBox(DynamicPrintConfig *config); + virtual ~AstroBox(); + + virtual const char* get_name() const; + + virtual bool test(wxString &curl_msg) const; + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; + virtual bool has_auto_discovery() const; + virtual bool can_test() const; + virtual bool can_start_print() const; + virtual std::string get_host() const { return host; } + +protected: + virtual bool validate_version_text(const boost::optional &version_text) const; + +private: + std::string host; + std::string apikey; + std::string cafile; + + void set_auth(Http &http) const; + std::string make_url(const std::string &path) const; +}; + + +class SL1Host: public AstroBox +{ +public: + SL1Host(DynamicPrintConfig *config) : AstroBox(config) {} + virtual ~SL1Host(); + + virtual const char* get_name() const; + + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; + virtual bool can_start_print() const ; +protected: + virtual bool validate_version_text(const boost::optional &version_text) const; +}; + + +} + +#endif diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 59a929ecca..0a49b78153 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -15,6 +15,7 @@ #include "OctoPrint.hpp" #include "Duet.hpp" #include "FlashAir.hpp" +#include "AstroBox.hpp" #include "../GUI/PrintHostDialogs.hpp" namespace fs = boost::filesystem; @@ -45,6 +46,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) case htOctoPrint: return new OctoPrint(config); case htDuet: return new Duet(config); case htFlashAir: return new FlashAir(config); + case htAstroBox: return new AstroBox(config); default: return nullptr; } } else { From b08a315a469c38f23a30908e2cf6170c11e90ad1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 6 Jan 2020 10:34:13 +0100 Subject: [PATCH 156/162] Fix of #3359: Ender icon case was not matching profile name Also added an icon to show when the correct one is not found --- resources/icons/printer_placeholder.png | Bin 0 -> 2936 bytes .../{Creality_Ender3.png => Creality_ENDER3.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/icons/printer_placeholder.png rename resources/icons/printers/{Creality_Ender3.png => Creality_ENDER3.png} (100%) diff --git a/resources/icons/printer_placeholder.png b/resources/icons/printer_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..8274019d83e2883c6e7d62d1fa6aa313f27b1154 GIT binary patch literal 2936 zcmeH}**6=C7RHel)fjH|P^mF>sv7DTj{fX@3q%nzj*r_7NQ~`5k5XXQ7cO` z_>oue@$vHs3mzrVw8#9B9eZG6MIys5)ObH8%&UlbK$;(a*?aekyH*bx@y=dSE8!I1I z&%fZWX?`tHRm9EKf##inlX5&=k&&0%cKV;{f42=)%=fdU4PX$gp;-e^V@JIa#%f4e zO!4D?@#P$4fedp7*lb2|RW41sxgI*Sck^PiA3g`@jNl#SuIg5H456NW{`^Q=KNTDa z8()|TjL94&PEcB^FA(d0X`WMU8l-A4F#MEM_i*;9nEg^BN{TCpTHA8esVOc_6Ea>9 zCti2`vFRqC1*7zyR1ZYD{>@8a%nr0JIIszeq}r0$-Vg}yU>+r_nCc4!O`}JD`*}WH zS2orJloJ!{bv*GAeWMJ57Xwp zQ>wY*8e&r}vJ0(i`NP#|U`*(qU>Wcg!uy^oq4ScES%1i3?yKncFLbM`#79r`G&!9@MrEjs1%|BkZ!d=m z27CId_4%GXT+s3Ywsi)%rYhBzZpDlqi*24A|Ae`^ZApV%Rl>{9Sx)>0t*hw?7%2f` z9&)r4O*aQD_R9~qmkPsgC$)A{rct6(KUw||ztTvhKEn3IyIJy?L}oMxE(s|GZLVML zFLPL^I-tFex4SfZUyTI4WqwD;u4(nSx9#~Zf3?1ib2m=BoWAaX9dFs(Li>wU%x>vO z7H$2}Sk{FL!^zc@HBn=rb0#~N1F%o-1h++-5cHa7_SI~X0TGuP;pKWVatL})S;V4B zV?$_Xna(v|{w5o?gK^uqtZw^Fm`^~kl6LcG3wd<%6BYcrk!9oqAp~;i6m_1I>x`tN zGC$G>n^gqR`GrN{3-{CW_1mJqiWVcC!!S=-EMdKL{se!K(b)<8>Vky)gvw_!Kfx#I zdqIDt+G4^pyS+R~b;vl@T*HLb<%I2TKm`7;dWiKDOOU?cQ-M#`%JIu^hc}P43C7EK z6V9)zbv}!L&zWpH+b@3|*iL`CV}}loTeODo6Ny(9?F@=ZmsX7Meif!xj&X)Uw=)T^ zU0vW}v62C91cb07tDaC%LddN7BWQHaVf#RuXOpkpefEMI5mj(Bz38ii0qs|c5|>C|*}ObRpZgn6Ps$2pbBYlaFoPa>te-sw z+6SciYH5k`+^ntTI&39=pm&6^j%X}x?EbYNv5V}2Zd_{SyzUm>;i^vuY>mbjujYFb z&iHzf$XDhb!G4Ad&76U5P zVw_JOycJxo2|UWks0>p};ft9?qdm&6~PVm^b;{qb-LOdMDaH5I*)_Gy_pVYdxnCqgAcc@{8KO;@emVMZ z%FxD$vHX4^FDZqyl+PuNpG}uFVAUWOGX=RcObB}x8|3|W*{$H_LZ)SIP?XSwh}iR@ z)ue2>oV$d`QXz0;WCrArJ^gblaGxBAH)Gfogb8qlBV6chg(`G>%r4ansNEFs%D=DZm;!!`0}*GLyBpCS$j%X%4?3-J#mX?Ju%(%_ovHoyBIm9@ zgH+40kS(FUbeEaGr~C*uDOKC(1}YlOF-`xh(2*ws%F0r8j}*HCZG$&@;cI$2ZhC2j zF^#J{kDbN~=~q;DoT3WRfuA%PtW`pn%{{9Y&@p$;rWyw(`d#A^u;KkFN0Tx+L`%Ro&*} zA(%K!X?<`_!M^KB?+1g@04g|&=;?i76~BuxKoN3g+Av;G(&Y6`)(HLU^UsYGvcPtw zyf^2Bhng03!fW6?Q&7fAR>?zP8OgjFpfKv=3h$5E=zL?{d)eVdqG?38W->X5_hYEl z8A{QroIfFiU8TVcvR9v+4B_qXO)OIZzy?V{n)=FENC6L;o_1e=zC)PKI5F{CXCZW~quFB#uy; O&&vFU*(a0Rxc>mZu5M8P literal 0 HcmV?d00001 diff --git a/resources/icons/printers/Creality_Ender3.png b/resources/icons/printers/Creality_ENDER3.png similarity index 100% rename from resources/icons/printers/Creality_Ender3.png rename to resources/icons/printers/Creality_ENDER3.png From 791f487c76d5a5f07609a93e584f9b518247319c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 6 Jan 2020 10:59:46 +0100 Subject: [PATCH 157/162] Clean-up of the "Upload to" code (AstroBox, Duet, FlashAir, OctoPrint) --- src/slic3r/Utils/AstroBox.cpp | 45 ---------------------------------- src/slic3r/Utils/AstroBox.hpp | 41 +++++++++---------------------- src/slic3r/Utils/Duet.cpp | 17 ------------- src/slic3r/Utils/Duet.hpp | 23 ++++++++--------- src/slic3r/Utils/FlashAir.cpp | 17 ------------- src/slic3r/Utils/FlashAir.hpp | 22 ++++++++--------- src/slic3r/Utils/OctoPrint.cpp | 26 -------------------- src/slic3r/Utils/OctoPrint.hpp | 36 +++++++++++++-------------- 8 files changed, 48 insertions(+), 179 deletions(-) diff --git a/src/slic3r/Utils/AstroBox.cpp b/src/slic3r/Utils/AstroBox.cpp index ded03ed4ce..83a72e64a0 100644 --- a/src/slic3r/Utils/AstroBox.cpp +++ b/src/slic3r/Utils/AstroBox.cpp @@ -28,8 +28,6 @@ AstroBox::AstroBox(DynamicPrintConfig *config) : cafile(config->opt_string("printhost_cafile")) {} -AstroBox::~AstroBox() {} - const char* AstroBox::get_name() const { return "AstroBox"; } bool AstroBox::test(wxString &msg) const @@ -142,21 +140,6 @@ bool AstroBox::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error return res; } -bool AstroBox::has_auto_discovery() const -{ - return true; -} - -bool AstroBox::can_test() const -{ - return true; -} - -bool AstroBox::can_start_print() const -{ - return true; -} - bool AstroBox::validate_version_text(const boost::optional &version_text) const { return version_text ? boost::starts_with(*version_text, "AstroBox") : true; @@ -184,32 +167,4 @@ std::string AstroBox::make_url(const std::string &path) const } } - -// SL1Host - -SL1Host::~SL1Host() {} - -const char* SL1Host::get_name() const { return "SL1Host"; } - -wxString SL1Host::get_test_ok_msg () const -{ - return _(L("Connection to Prusa SL1 works correctly.")); -} - -wxString SL1Host::get_test_failed_msg (wxString &msg) const -{ - return wxString::Format("%s: %s", _(L("Could not connect to Prusa SLA")), msg); -} - -bool SL1Host::can_start_print() const -{ - return false; -} - -bool SL1Host::validate_version_text(const boost::optional &version_text) const -{ - return version_text ? boost::starts_with(*version_text, "Prusa SLA") : false; -} - - } diff --git a/src/slic3r/Utils/AstroBox.hpp b/src/slic3r/Utils/AstroBox.hpp index 1474132da6..38542275c5 100644 --- a/src/slic3r/Utils/AstroBox.hpp +++ b/src/slic3r/Utils/AstroBox.hpp @@ -7,10 +7,8 @@ #include "PrintHost.hpp" - namespace Slic3r { - class DynamicPrintConfig; class Http; @@ -18,21 +16,21 @@ class AstroBox : public PrintHost { public: AstroBox(DynamicPrintConfig *config); - virtual ~AstroBox(); + ~AstroBox() override = default; - virtual const char* get_name() const; + const char* get_name() const override; - virtual bool test(wxString &curl_msg) const; - virtual wxString get_test_ok_msg () const; - virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; - virtual bool has_auto_discovery() const; - virtual bool can_test() const; - virtual bool can_start_print() const; - virtual std::string get_host() const { return host; } + bool test(wxString &curl_msg) const override; + wxString get_test_ok_msg () const override; + wxString get_test_failed_msg (wxString &msg) const override; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; + bool has_auto_discovery() const override { return true; } + bool can_test() const override { return true; } + bool can_start_print() const override { return true; } + std::string get_host() const override { return host; } protected: - virtual bool validate_version_text(const boost::optional &version_text) const; + bool validate_version_text(const boost::optional &version_text) const; private: std::string host; @@ -43,23 +41,6 @@ private: std::string make_url(const std::string &path) const; }; - -class SL1Host: public AstroBox -{ -public: - SL1Host(DynamicPrintConfig *config) : AstroBox(config) {} - virtual ~SL1Host(); - - virtual const char* get_name() const; - - virtual wxString get_test_ok_msg () const; - virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool can_start_print() const ; -protected: - virtual bool validate_version_text(const boost::optional &version_text) const; -}; - - } #endif diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index b0d8c0b8d7..554d3f5f55 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -32,8 +32,6 @@ Duet::Duet(DynamicPrintConfig *config) : password(config->opt_string("printhost_apikey")) {} -Duet::~Duet() {} - const char* Duet::get_name() const { return "Duet"; } bool Duet::test(wxString &msg) const @@ -111,21 +109,6 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e return res; } -bool Duet::has_auto_discovery() const -{ - return false; -} - -bool Duet::can_test() const -{ - return true; -} - -bool Duet::can_start_print() const -{ - return true; -} - bool Duet::connect(wxString &msg) const { bool res = false; diff --git a/src/slic3r/Utils/Duet.hpp b/src/slic3r/Utils/Duet.hpp index 04ceec36fd..702efbddb6 100644 --- a/src/slic3r/Utils/Duet.hpp +++ b/src/slic3r/Utils/Duet.hpp @@ -6,10 +6,8 @@ #include "PrintHost.hpp" - namespace Slic3r { - class DynamicPrintConfig; class Http; @@ -17,18 +15,18 @@ class Duet : public PrintHost { public: Duet(DynamicPrintConfig *config); - virtual ~Duet(); + ~Duet() override = default; - virtual const char* get_name() const; + const char* get_name() const override; - virtual bool test(wxString &curl_msg) const; - virtual wxString get_test_ok_msg () const; - virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; - virtual bool has_auto_discovery() const; - virtual bool can_test() const; - virtual bool can_start_print() const; - virtual std::string get_host() const { return host; } + bool test(wxString &curl_msg) const override; + wxString get_test_ok_msg() const override; + wxString get_test_failed_msg(wxString &msg) const override; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; + bool has_auto_discovery() const override { return false; } + bool can_test() const override { return true; } + bool can_start_print() const override { return true; } + std::string get_host() const override { return host; } private: std::string host; @@ -44,7 +42,6 @@ private: int get_err_code_from_body(const std::string &body) const; }; - } #endif diff --git a/src/slic3r/Utils/FlashAir.cpp b/src/slic3r/Utils/FlashAir.cpp index 3fc913c994..79f3f2c2bd 100644 --- a/src/slic3r/Utils/FlashAir.cpp +++ b/src/slic3r/Utils/FlashAir.cpp @@ -30,8 +30,6 @@ FlashAir::FlashAir(DynamicPrintConfig *config) : host(config->opt_string("print_host")) {} -FlashAir::~FlashAir() {} - const char* FlashAir::get_name() const { return "FlashAir"; } bool FlashAir::test(wxString &msg) const @@ -150,21 +148,6 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error return res; } -bool FlashAir::has_auto_discovery() const -{ - return false; -} - -bool FlashAir::can_test() const -{ - return true; -} - -bool FlashAir::can_start_print() const -{ - return false; -} - std::string FlashAir::timestamp_str() const { auto t = std::time(nullptr); diff --git a/src/slic3r/Utils/FlashAir.hpp b/src/slic3r/Utils/FlashAir.hpp index 1499eee5d8..40af48da1b 100644 --- a/src/slic3r/Utils/FlashAir.hpp +++ b/src/slic3r/Utils/FlashAir.hpp @@ -9,7 +9,6 @@ namespace Slic3r { - class DynamicPrintConfig; class Http; @@ -17,18 +16,18 @@ class FlashAir : public PrintHost { public: FlashAir(DynamicPrintConfig *config); - virtual ~FlashAir(); + ~FlashAir() override = default; - virtual const char* get_name() const; + const char* get_name() const override; - virtual bool test(wxString &curl_msg) const; - virtual wxString get_test_ok_msg () const; - virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; - virtual bool has_auto_discovery() const; - virtual bool can_test() const; - virtual bool can_start_print() const; - virtual std::string get_host() const { return host; } + bool test(wxString &curl_msg) const override; + wxString get_test_ok_msg() const override; + wxString get_test_failed_msg(wxString &msg) const override; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; + bool has_auto_discovery() const override { return false; } + bool can_test() const override { return true; } + bool can_start_print() const override { return false; } + std::string get_host() const override { return host; } private: std::string host; @@ -38,7 +37,6 @@ private: std::string make_url(const std::string &path, const std::string &arg, const std::string &val) const; }; - } #endif diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index 09ca02071a..48f8ba0b9a 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -28,8 +28,6 @@ OctoPrint::OctoPrint(DynamicPrintConfig *config) : cafile(config->opt_string("printhost_cafile")) {} -OctoPrint::~OctoPrint() {} - const char* OctoPrint::get_name() const { return "OctoPrint"; } bool OctoPrint::test(wxString &msg) const @@ -142,21 +140,6 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro return res; } -bool OctoPrint::has_auto_discovery() const -{ - return true; -} - -bool OctoPrint::can_test() const -{ - return true; -} - -bool OctoPrint::can_start_print() const -{ - return true; -} - bool OctoPrint::validate_version_text(const boost::optional &version_text) const { return version_text ? boost::starts_with(*version_text, "OctoPrint") : true; @@ -186,9 +169,6 @@ std::string OctoPrint::make_url(const std::string &path) const // SL1Host - -SL1Host::~SL1Host() {} - const char* SL1Host::get_name() const { return "SL1Host"; } wxString SL1Host::get_test_ok_msg () const @@ -201,15 +181,9 @@ wxString SL1Host::get_test_failed_msg (wxString &msg) const return wxString::Format("%s: %s", _(L("Could not connect to Prusa SLA")), msg); } -bool SL1Host::can_start_print() const -{ - return false; -} - bool SL1Host::validate_version_text(const boost::optional &version_text) const { return version_text ? boost::starts_with(*version_text, "Prusa SLA") : false; } - } diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 0e372c7c95..965019d859 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -10,7 +10,6 @@ namespace Slic3r { - class DynamicPrintConfig; class Http; @@ -18,18 +17,18 @@ class OctoPrint : public PrintHost { public: OctoPrint(DynamicPrintConfig *config); - virtual ~OctoPrint(); + ~OctoPrint() override = default; - virtual const char* get_name() const; + const char* get_name() const; - virtual bool test(wxString &curl_msg) const; - virtual wxString get_test_ok_msg () const; - virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; - virtual bool has_auto_discovery() const; - virtual bool can_test() const; - virtual bool can_start_print() const; - virtual std::string get_host() const { return host; } + bool test(wxString &curl_msg) const override; + wxString get_test_ok_msg () const override; + wxString get_test_failed_msg (wxString &msg) const override; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; + bool has_auto_discovery() const override { return true; } + bool can_test() const override { return true; } + bool can_start_print() const override { return true; } + std::string get_host() const override { return host; } protected: virtual bool validate_version_text(const boost::optional &version_text) const; @@ -43,23 +42,22 @@ private: std::string make_url(const std::string &path) const; }; - class SL1Host: public OctoPrint { public: SL1Host(DynamicPrintConfig *config) : OctoPrint(config) {} - virtual ~SL1Host(); + ~SL1Host() override = default; - virtual const char* get_name() const; + const char* get_name() const override; + + wxString get_test_ok_msg() const override; + wxString get_test_failed_msg(wxString &msg) const override; + bool can_start_print() const override { return false; } - virtual wxString get_test_ok_msg () const; - virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool can_start_print() const ; protected: - virtual bool validate_version_text(const boost::optional &version_text) const; + bool validate_version_text(const boost::optional &version_text) const override; }; - } #endif From 704e10c55a51492c65829985cb2947c6e9a86862 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 6 Jan 2020 11:32:17 +0100 Subject: [PATCH 158/162] Replaced unix basename() with boost::filesystem::basename(), as various unices define basename() differently. --- src/slic3r/GUI/RemovableDriveManager.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 9ef31748de..8586cf4748 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -21,6 +21,7 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, #include #include #include +#include #endif namespace Slic3r { @@ -321,14 +322,8 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str uid_t uid = buf.st_uid; std::string username(std::getenv("USER")); struct passwd *pw = getpwuid(uid); - if(pw != 0) - { - if(pw->pw_name == username) - { - std::string name = basename(path.data()); - m_current_drives.push_back(DriveData(name,path)); - } - } + if (pw != 0 && pw->pw_name == username) + m_current_drives.push_back(DriveData(boost::filesystem::basename(boost::filesystem::path(path)), path)); } } From 5078604182459d796ef4e410a6b070ac4399576f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 6 Jan 2020 11:59:24 +0100 Subject: [PATCH 159/162] Trying to fix Linux compilation --- src/slic3r/GUI/RemovableDriveManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 8586cf4748..5041e21205 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -18,7 +18,6 @@ GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, #include #include #include -#include #include #include #include @@ -240,10 +239,8 @@ void RemovableDriveManager::search_for_drives() //search /media/* folder search_path("/media/*", "/media"); -/* //search /Volumes/* folder (OSX) - search_path("/Volumes/*", "/Volumes"); -*/ + //search_path("/Volumes/*", "/Volumes"); std::string path(std::getenv("USER")); std::string pp(path); //std::cout << "user: "<< path << "\n"; From 68d0f5b4ef76bbc5e1bd59b5246f75123828b459 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 6 Jan 2020 12:07:23 +0100 Subject: [PATCH 160/162] Corrected description of --loglevel parameter on command line output --- src/libslic3r/PrintConfig.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 0835693b2e..761507a2e9 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3435,7 +3435,8 @@ CLIMiscConfigDef::CLIMiscConfigDef() def = this->add("loglevel", coInt); def->label = L("Logging level"); - def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal"); + def->tooltip = L("Sets logging sensitivity. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n" + "For example. loglevel=2 logs fatal, error and warning level messages."); def->min = 0; #if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI) From c790e2ff7c925252b1f83d54154cf858d6eb5afa Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 6 Jan 2020 12:10:57 +0100 Subject: [PATCH 161/162] Added unit test for checking geometry after save+load to 3mf cycle --- src/libslic3r/Format/3mf.cpp | 4 +- tests/data/test_3mf/Prusa.stl | Bin 0 -> 30784 bytes tests/libslic3r/test_3mf.cpp | 71 +++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 tests/data/test_3mf/Prusa.stl diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index b485e83d86..44e12db865 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -716,8 +716,8 @@ namespace Slic3r { return false; } - // fixes the min z of the model if negative - model.adjust_min_z(); +// // fixes the min z of the model if negative +// model.adjust_min_z(); return true; } diff --git a/tests/data/test_3mf/Prusa.stl b/tests/data/test_3mf/Prusa.stl new file mode 100644 index 0000000000000000000000000000000000000000..049cbaceea669b9cd7e6d884424acd4744de2918 GIT binary patch literal 30784 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�lQ_>>y2xwene$%K|@49(E5xf0rL8rvtd&-r|g+_|b2uLoBR z3RQg4j}uy=el?z-mG-l$G+Uq0KIaN8GD&VL-H*~;EB}dJ`&>)ZuX^&c;xjTb(YH|e zbRTakeR5Zo(tZrhicj(ItF%vOR;p6kCv=@kGfd8k`_9Njci;SXytH+7zfO1G{I{u+ z2=%M+{CenapRO(F&Yw?cbj>Q6;0gq4&i5W&f7HIc2iuRK`<%MA;J+KCHP_sgP)~jg zRq2XHaty79s+9I)Xl=Rn-f+!zm0ZVI^0?9x%}PD_S!pJ!QrahU?CQAk-?GsDP?f&7 z;=dcEg!)oCncy2VXi-&ZJii|Nasvo{-2t}$YjVws-%co0DecG568!?Zdh!YVs8t&@84V`%QGQrai*gw5Zw!{+}t!7oU}vr?6g z{A7Y(ihwUwDeY&aXO4dNA(>E>#!Dvn9fra_(7y4r(h^;bP)|OgUv5y9(mtW9DoXoA z)8{MK4x4T}ar#>c{S5_e>%n3KRPC$FXngsNy;44oPD z{XPB$2Y&gRAB&*`eW65YpP2B<#BB5HCq*E&gf=pvC(9~{P!;WXR=RQrn{UuzU90}p zTA!#>aV3l~>VAXe6SjVN<=)q=W<1y!SIGpjQlh>X@l4P@4P{mLzvyUfX=|TbW_U)f zYaeYZvsn-HT`~a`p4C|=|BT`t8EVM;IoNzYXU!1#WgYz^{tB~TwJ!alge#D+{j5HiIWcJe{XDm_ zt!sT$AuHMzqZk1dJsE*~?5}e7yrh0%lYs57x3eB7VLf2;csz!VMA%#lO>Qf$N5hw@ zlt!P|?Zhz#XJ^LXam(uTKVBK!*vZ}`SHJbevzjYG6-r3M=J9yV*(QaAwj0MTdZg0Z zgV42UjYq=H51l_~9IqhM6Jyx;r3(4d z27&9YX627|mT-hKE5`O?Xbsh`wunz?`>2Yxwyup`J`bV<{mlO@jn9U0g6j+@(cY|Y zlvoTt@q*YS|NmSvp(UD?dScD%Vz6~JccpzoOZZJ{WTAh^~V)QA4i7vzh4i1PeR{%DSQJ0HNaox?(beBy1uufv>!vi_^jWgPA0SjHurA* z?>bvXmX(fne&ZP#D(z>bCHxi+2=(OmU}0ALG9Ep}d$5q;*C using namespace Slic3r; SCENARIO("Reading 3mf file", "[3mf]") { GIVEN("umlauts in the path of the file") { - Slic3r::Model model; + Model model; WHEN("3mf model is read") { std::string path = std::string(TEST_DATA_DIR) + "/test_3mf/Geräte/Büchse.3mf"; DynamicPrintConfig config; - bool ret = Slic3r::load_3mf(path.c_str(), &config, &model, false); + bool ret = load_3mf(path.c_str(), &config, &model, false); THEN("load should succeed") { REQUIRE(ret); } } } } + +SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") { + GIVEN("world vertices coordinates before save") { + // load a model from stl file + Model src_model; + std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.stl"; + load_stl(src_file.c_str(), &src_model); + src_model.add_default_instances(); + + ModelObject* src_object = src_model.objects[0]; + + // apply generic transformation to the 1st volume + Geometry::Transformation src_volume_transform; + src_volume_transform.set_offset(Vec3d(10.0, 20.0, 0.0)); + src_volume_transform.set_rotation(Vec3d(Geometry::deg2rad(25.0), Geometry::deg2rad(35.0), Geometry::deg2rad(45.0))); + src_volume_transform.set_scaling_factor(Vec3d(1.1, 1.2, 1.3)); + src_volume_transform.set_mirror(Vec3d(-1.0, 1.0, -1.0)); + src_object->volumes[0]->set_transformation(src_volume_transform); + + // apply generic transformation to the 1st instance + Geometry::Transformation src_instance_transform; + src_instance_transform.set_offset(Vec3d(5.0, 10.0, 0.0)); + src_instance_transform.set_rotation(Vec3d(Geometry::deg2rad(12.0), Geometry::deg2rad(13.0), Geometry::deg2rad(14.0))); + src_instance_transform.set_scaling_factor(Vec3d(0.9, 0.8, 0.7)); + src_instance_transform.set_mirror(Vec3d(1.0, -1.0, -1.0)); + src_object->instances[0]->set_transformation(src_instance_transform); + + WHEN("model is saved+loaded to/from 3mf file") { + // save the model to 3mf file + std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.3mf"; + store_3mf(test_file.c_str(), &src_model, nullptr); + + // load back the model from the 3mf file + Model dst_model; + DynamicPrintConfig dst_config; + load_3mf(test_file.c_str(), &dst_config, &dst_model, false); + boost::filesystem::remove(test_file); + + // compare meshes + TriangleMesh src_mesh = src_model.mesh(); + src_mesh.repair(); + + TriangleMesh dst_mesh = dst_model.mesh(); + dst_mesh.repair(); + + bool res = src_mesh.its.vertices.size() == dst_mesh.its.vertices.size(); + if (res) + { + for (size_t i = 0; i < dst_mesh.its.vertices.size(); ++i) + { + res &= dst_mesh.its.vertices[i].isApprox(src_mesh.its.vertices[i]); + if (!res) + { + Vec3f diff = dst_mesh.its.vertices[i] - src_mesh.its.vertices[i]; + std::cout << i << ": diff " << to_string((Vec3d)diff.cast()) << "\n"; + } + } + } + THEN("world vertices coordinates after load match") { + REQUIRE(res); + } + } + } +} From 8fd753ab2758e9c4452e4f0863ebfd41ed0dda4d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 6 Jan 2020 12:31:35 +0100 Subject: [PATCH 162/162] Follow-up of c790e2ff7c925252b1f83d54154cf858d6eb5afa -> Fixed include --- tests/libslic3r/test_3mf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index 26b2c119f2..5215e2ebd2 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -2,7 +2,7 @@ #include "libslic3r/Model.hpp" #include "libslic3r/Format/3mf.hpp" -#include "libslic3r/Format/stl.hpp" +#include "libslic3r/Format/STL.hpp" #include