diff --git a/resources/icons/notification_eject_sd.svg b/resources/icons/notification_eject_sd.svg
new file mode 100644
index 0000000000..bea6c09772
--- /dev/null
+++ b/resources/icons/notification_eject_sd.svg
@@ -0,0 +1,75 @@
+
+
diff --git a/resources/icons/notification_eject_sd_hover.svg b/resources/icons/notification_eject_sd_hover.svg
new file mode 100644
index 0000000000..23d2480c62
--- /dev/null
+++ b/resources/icons/notification_eject_sd_hover.svg
@@ -0,0 +1,76 @@
+
+
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index 4a1d1faa0c..fc635dfac6 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -121,6 +121,8 @@ namespace ImGui
const char MinimalizeHoverMarker = 0xF;
const char WarningMarker = 0x10;
const char ErrorMarker = 0x11;
+ const char EjectMarker = 0x12;
+ const char EjectHoverMarker = 0x13;
// void MyFunction(const char* name, const MyMatrix44& v);
}
diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp
index 2bef204ad3..2879055335 100644
--- a/src/libslic3r/Exception.hpp
+++ b/src/libslic3r/Exception.hpp
@@ -20,6 +20,7 @@ SLIC3R_DERIVE_EXCEPTION(OutOfRange, LogicError);
SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException);
SLIC3R_DERIVE_EXCEPTION(FileIOError, IOError);
SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError);
+SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException);
// Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications.
SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception);
#undef SLIC3R_DERIVE_EXCEPTION
diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp
index 7a95829cd0..cebafa6333 100644
--- a/src/libslic3r/Zipper.cpp
+++ b/src/libslic3r/Zipper.cpp
@@ -25,12 +25,12 @@ public:
std::string formatted_errorstr() const
{
return L("Error with zip archive") + " " + m_zipname + ": " +
- get_errorstr() + "!";
+ get_errorstr();
}
SLIC3R_NORETURN void blow_up() const
{
- throw Slic3r::RuntimeError(formatted_errorstr());
+ throw Slic3r::ExportError(formatted_errorstr());
}
bool is_alive()
diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp
index 886dcf46a9..2c55c5a0e4 100644
--- a/src/libslic3r/utils.cpp
+++ b/src/libslic3r/utils.cpp
@@ -429,24 +429,20 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
// 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.
-
- //This error code is ignored
boost::system::error_code ec;
-
boost::filesystem::permissions(target, perms, ec);
- //if (ec)
- // BOOST_LOG_TRIVIAL(error) << "Copy file permisions before copy error message: " << ec.message();
- // This error code is passed up
+ if (ec)
+ BOOST_LOG_TRIVIAL(error) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
ec.clear();
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
error_message = ec.message();
return FAIL_COPY_FILE;
}
- //ec.clear();
+ ec.clear();
boost::filesystem::permissions(target, perms, ec);
- //if (ec)
- // BOOST_LOG_TRIVIAL(error) << "Copy file permisions after copy error message: " << ec.message();
+ if (ec)
+ BOOST_LOG_TRIVIAL(error) << "boost::filesystem::permisions after copy error message (this could be irrelevant message based on file system): " << ec.message();
return SUCCESS;
}
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 36187f81ec..2f3c40ace8 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -53,6 +53,24 @@ bool SlicingProcessCompletedEvent::critical_error() const
return true;
}
+bool SlicingProcessCompletedEvent::invalidate_plater() const
+{
+ if (critical_error())
+ {
+ try {
+ this->rethrow_exception();
+ }
+ catch (const Slic3r::ExportError&) {
+ // Exception thrown by copying file does not ivalidate plater
+ return false;
+ }
+ catch (...) {
+ }
+ return true;
+ }
+ return false;
+}
+
std::string SlicingProcessCompletedEvent::format_error_message() const
{
std::string error;
@@ -142,19 +160,19 @@ void BackgroundSlicingProcess::process_fff()
switch (copy_ret_val) {
case SUCCESS: break; // no error
case FAIL_COPY_FILE:
- throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
+ throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
break;
case FAIL_FILES_DIFFERENT:
- throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
+ throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
break;
case FAIL_RENAMING:
- throw Slic3r::RuntimeError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
+ throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
break;
case FAIL_CHECK_ORIGIN_NOT_OPENED:
- throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
+ throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
break;
case FAIL_CHECK_TARGET_NOT_OPENED:
- throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
+ throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
break;
default:
throw Slic3r::RuntimeError(_utf8(L("Unknown error occured during exporting G-code.")));
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
index 1b2687e63a..e6314068ec 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
@@ -57,6 +57,8 @@ public:
bool error() const { return m_status == Error; }
// Unhandled error produced by stdlib or a Win32 structured exception, or unhandled Slic3r's own critical exception.
bool critical_error() const;
+ // Critical errors does invalidate plater except CopyFileError.
+ bool invalidate_plater() const;
// Only valid if error()
void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); }
// Produce a human readable message to be displayed by a notification or a message box.
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index d759f4b9af..e468ffbb59 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -49,7 +49,9 @@ static const std::map font_icons = {
{ImGui::MinimalizeMarker , "notification_minimalize" },
{ImGui::MinimalizeHoverMarker , "notification_minimalize_hover" },
{ImGui::WarningMarker , "notification_warning" },
- {ImGui::ErrorMarker , "notification_error" }
+ {ImGui::ErrorMarker , "notification_error" },
+ {ImGui::EjectMarker , "notification_eject_sd" },
+ {ImGui::EjectHoverMarker , "notification_eject_sd_hover" },
};
const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f };
diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp
index 8516a4419d..a1bb48d2bc 100644
--- a/src/slic3r/GUI/NotificationManager.cpp
+++ b/src/slic3r/GUI/NotificationManager.cpp
@@ -1,6 +1,7 @@
#include "NotificationManager.hpp"
#include "GUI_App.hpp"
+#include "GUI.hpp"
#include "Plater.hpp"
#include "GLCanvas3D.hpp"
#include "ImGuiWrapper.hpp"
@@ -33,6 +34,56 @@ namespace Notifications_Internal{
else
ImGui::PushStyleColor(idx, col);
}
+
+ void open_folder(const std::string& path)
+ {
+ // Code taken from desktop_open_datadir_folder()
+
+ // Execute command to open a file explorer, platform dependent.
+ // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade.
+
+#ifdef _WIN32
+ const wxString widepath = from_u8(path);
+ const wchar_t* argv[] = { L"explorer", widepath.GetData(), nullptr };
+ ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr);
+#elif __APPLE__
+ const char* argv[] = { "open", path.data(), nullptr };
+ ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr);
+#else
+ const char* argv[] = { "xdg-open", path.data(), nullptr };
+
+ // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars,
+ // because they may mess up the environment expected by the file manager.
+ // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure.
+ if (wxGetEnv("APPIMAGE", nullptr)) {
+ // We're running from AppImage
+ wxEnvVariableHashMap env_vars;
+ wxGetEnvMap(&env_vars);
+
+ env_vars.erase("APPIMAGE");
+ env_vars.erase("APPDIR");
+ env_vars.erase("LD_LIBRARY_PATH");
+ env_vars.erase("LD_PRELOAD");
+ env_vars.erase("UNION_PRELOAD");
+
+ wxExecuteEnv exec_env;
+ exec_env.env = std::move(env_vars);
+
+ wxString owd;
+ if (wxGetEnv("OWD", &owd)) {
+ // This is the original work directory from which the AppImage image was run,
+ // set it as CWD for the child process:
+ exec_env.cwd = std::move(owd);
+ }
+
+ ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env);
+ }
+ else {
+ // Looks like we're NOT running from AppImage, we'll make no changes to the environment.
+ ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr);
+ }
+#endif
+ }
}
#if 1
@@ -183,6 +234,7 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif
render_left_sign(imgui);
render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
+ m_minimize_b_visible = false;
if (m_multiline && m_lines_count > 3)
render_minimize_button(imgui, win_pos.x, win_pos.y);
} else {
@@ -205,12 +257,8 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif
ImGui::PopStyleColor();
return ret_val;
}
-void NotificationManager::PopNotification::init()
+void NotificationManager::PopNotification::count_spaces()
{
- std::string text = m_text1 + " " + m_hypertext;
- int last_end = 0;
- m_lines_count = 0;
-
//determine line width
m_line_height = ImGui::CalcTextSize("A").y;
@@ -221,8 +269,16 @@ void NotificationManager::PopNotification::init()
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
m_left_indentation = picture_width + m_line_height / 2;
}
- m_window_width_offset = m_left_indentation + m_line_height * 2;
+ m_window_width_offset = m_left_indentation + m_line_height * 3.f;
m_window_width = m_line_height * 25;
+}
+void NotificationManager::PopNotification::init()
+{
+ std::string text = m_text1 + " " + m_hypertext;
+ int last_end = 0;
+ m_lines_count = 0;
+
+ count_spaces();
// count lines
m_endlines.clear();
@@ -233,10 +289,9 @@ void NotificationManager::PopNotification::init()
//next line is ended by '/n'
m_endlines.push_back(next_hard_end);
last_end = next_hard_end + 1;
- }
- else {
+ } else {
// find next suitable endline
- if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - 3.5f * m_line_height) {// m_window_width_offset) {
+ if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
// more than one line till end
int next_space = text.find_first_of(' ', last_end);
if (next_space > 0) {
@@ -245,8 +300,19 @@ void NotificationManager::PopNotification::init()
next_space = next_space_candidate;
next_space_candidate = text.find_first_of(' ', next_space + 1);
}
- m_endlines.push_back(next_space);
- last_end = next_space + 1;
+ // when one word longer than line.
+ if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset) {
+ float width_of_a = ImGui::CalcTextSize("a").x;
+ int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
+ while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) {
+ letter_count++;
+ }
+ m_endlines.push_back(last_end + letter_count);
+ last_end += letter_count;
+ } else {
+ m_endlines.push_back(next_space);
+ last_end = next_space + 1;
+ }
}
}
else {
@@ -257,6 +323,8 @@ void NotificationManager::PopNotification::init()
}
m_lines_count++;
}
+ if (m_lines_count == 3)
+ m_multiline = true;
m_initialized = true;
}
void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui)
@@ -285,7 +353,8 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
float shift_y = m_line_height;// -m_line_height / 20;
for (size_t i = 0; i < m_lines_count; i++) {
std::string line = m_text1.substr(last_end , m_endlines[i] - last_end);
- last_end = m_endlines[i] + 1;
+ if(i < m_lines_count - 1)
+ last_end = m_endlines[i] + (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(starting_y + i * shift_y);
imgui.text(line.c_str());
@@ -303,7 +372,7 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
// line2
- std::string line = m_text1.substr(m_endlines[0] + 1, m_endlines[1] - m_endlines[0] - 1);
+ std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
if (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x)
{
line = line.substr(0, line.length() - 6);
@@ -326,7 +395,7 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
// line2
- std::string line = m_text1.substr(m_endlines[0] + 1);
+ std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2;
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(cursor_y);
@@ -375,8 +444,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
set_next_window_size(imgui);
}
else {
- on_text_click();
- m_close_pending = true;
+ m_close_pending = on_text_click();
}
}
ImGui::PopStyleColor();
@@ -407,7 +475,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
- ImVec2 win_pos(win_pos_x, win_pos_y);
+ ImVec2 win_pos(win_pos_x, win_pos_y);
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
orange_color.w = 0.8f;
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
@@ -422,7 +490,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
button_text = ImGui::CloseIconMarker;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y),
- ImVec2(win_pos.x, win_pos.y + win_size.y - (m_multiline? 2 * m_line_height : 0)),
+ ImVec2(win_pos.x, win_pos.y + win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0)),
true))
{
button_text = ImGui::CloseIconHoverMarker;
@@ -435,11 +503,10 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
{
m_close_pending = true;
}
-
//invisible large button
- ImGui::SetCursorPosX(win_size.x - win_size.x / 10.f);
+ ImGui::SetCursorPosX(win_size.x - m_line_height * 2.125);
ImGui::SetCursorPosY(0);
- if (imgui.button(" ", win_size.x / 10.f, win_size.y - (m_multiline ? 2 * m_line_height : 0)))
+ if (imgui.button(" ", m_line_height * 2.125, win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0)))
{
m_close_pending = true;
}
@@ -540,15 +607,12 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper&
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
+ m_minimize_b_visible = true;
}
-void NotificationManager::PopNotification::on_text_click()
+bool NotificationManager::PopNotification::on_text_click()
{
+ bool ret = true;
switch (m_data.type) {
- case NotificationType::ExportToRemovableFinished :
- assert(m_evt_handler != nullptr);
- if (m_evt_handler != nullptr)
- wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
- break;
case NotificationType::SlicingComplete :
//wxGetApp().plater()->export_gcode(false);
assert(m_evt_handler != nullptr);
@@ -567,6 +631,7 @@ void NotificationManager::PopNotification::on_text_click()
default:
break;
}
+ return ret;
}
void NotificationManager::PopNotification::update(const NotificationData& n)
{
@@ -633,6 +698,127 @@ void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l)
m_hypertext = l ? _u8L("Export G-Code.") : std::string();
m_hidden = !l;
}
+//---------------ExportFinishedNotification-----------
+void NotificationManager::ExportFinishedNotification::count_spaces()
+{
+ //determine line width
+ m_line_height = ImGui::CalcTextSize("A").y;
+
+ m_left_indentation = m_line_height;
+ if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
+ std::string text;
+ text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
+ float picture_width = ImGui::CalcTextSize(text.c_str()).x;
+ m_left_indentation = picture_width + m_line_height / 2;
+ }
+ //TODO count this properly
+ m_window_width_offset = m_left_indentation + m_line_height * (m_to_removable ? 5.f : 3.f);
+ m_window_width = m_line_height * 25;
+}
+
+void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
+{
+
+ ImVec2 win_size(win_size_x, win_size_y);
+ ImVec2 win_pos(win_pos_x, win_pos_y);
+ float x_offset = m_left_indentation;
+ std::string fulltext = m_text1 + m_hypertext; //+ m_text2;
+ ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str());
+ // Lines are always at least two and m_multiline is always true for ExportFinishedNotification.
+ // First line has "Export Finished" text and than hyper text open folder.
+ // Following lines are path to gcode.
+ int last_end = 0;
+ float starting_y = m_line_height / 2;//10;
+ float shift_y = m_line_height;// -m_line_height / 20;
+ for (size_t i = 0; i < m_lines_count; i++) {
+ std::string line = m_text1.substr(last_end, m_endlines[i] - last_end);
+ if (i < m_lines_count - 1)
+ last_end = m_endlines[i] + (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
+ ImGui::SetCursorPosX(x_offset);
+ ImGui::SetCursorPosY(starting_y + i * shift_y);
+ imgui.text(line.c_str());
+ //hyperlink text
+ if ( i == 0 ) {
+ render_hypertext(imgui, x_offset + ImGui::CalcTextSize(m_text1.substr(0, last_end).c_str()).x + ImGui::CalcTextSize(" ").x, starting_y, _u8L("Open Folder."));
+ }
+ }
+
+}
+
+void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
+{
+ PopNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
+ if(m_to_removable)
+ render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
+}
+
+void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
+{
+ ImVec2 win_size(win_size_x, win_size_y);
+ ImVec2 win_pos(win_pos_x, win_pos_y);
+ ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
+ orange_color.w = 0.8f;
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
+ Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
+ Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
+
+ std::string button_text;
+ button_text = ImGui::EjectMarker;
+
+ if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 4.5f, win_pos.y),
+ ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y),
+ true))
+ {
+ button_text = ImGui::EjectHoverMarker;
+ // tooltip
+ long time_now = wxGetLocalTime();
+ if (m_hover_time > 0 && m_hover_time < time_now) {
+ ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
+ ImGui::BeginTooltip();
+ imgui.text(_u8L("Eject drive"));
+ ImGui::EndTooltip();
+ ImGui::PopStyleColor();
+ }
+ if (m_hover_time == 0)
+ m_hover_time = time_now;
+ } else
+ m_hover_time = 0;
+
+ ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
+ ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
+ ImGui::SetCursorPosX(win_size.x - m_line_height * 4.f);
+ ImGui::SetCursorPosY(win_size.y / 2 - button_size.y / 2);
+ if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
+ {
+ assert(m_evt_handler != nullptr);
+ if (m_evt_handler != nullptr)
+ wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
+ m_close_pending = true;
+ }
+
+ //invisible large button
+ ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f);
+ ImGui::SetCursorPosY(0);
+ if (imgui.button(" ", m_line_height * 2.f, win_size.y))
+ {
+ assert(m_evt_handler != nullptr);
+ if (m_evt_handler != nullptr)
+ wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
+ m_close_pending = true;
+ }
+ ImGui::PopStyleColor();
+ ImGui::PopStyleColor();
+ ImGui::PopStyleColor();
+ ImGui::PopStyleColor();
+ ImGui::PopStyleColor();
+}
+bool NotificationManager::ExportFinishedNotification::on_text_click()
+{
+ Notifications_Internal::open_folder(m_export_dir_path);
+ return false;
+}
//------NotificationManager--------
NotificationManager::NotificationManager(wxEvtHandler* evt_handler) :
m_evt_handler(evt_handler)
@@ -789,6 +975,13 @@ void NotificationManager::remove_slicing_warnings_of_released_objects(const std:
notification->close();
}
}
+void NotificationManager::push_exporting_finished_notification(GLCanvas3D& canvas, std::string path, std::string dir_path, bool on_removable)
+{
+ close_notification_of_type(NotificationType::ExportFinished);
+ NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, 0, _u8L("Exporting finished.") +"\n"+ path };
+ push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, on_removable, path, dir_path),
+ canvas, 0);
+}
bool NotificationManager::push_notification_data(const NotificationData ¬ification_data, GLCanvas3D& canvas, int timestamp)
{
return push_notification_data(std::make_unique(notification_data, m_id_provider, m_evt_handler), canvas, timestamp);
@@ -822,7 +1015,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay
bool hovered = false;
sort_notifications();
// iterate thru notifications and render them / erease them
- for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
+ for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
if ((*it)->get_finished()) {
it = m_pop_notifications.erase(it);
} else {
@@ -931,5 +1124,31 @@ bool NotificationManager::has_slicing_error_notification()
});
}
+void NotificationManager::new_export_began(bool on_removable)
+{
+ close_notification_of_type(NotificationType::ExportFinished);
+ // If we want to hold information of ejecting removable on later export finished notifications
+ /*
+ for (std::unique_ptr& notification : m_pop_notifications) {
+ if (notification->get_type() == NotificationType::ExportToRemovableFinished) {
+ if (!on_removable) {
+ const NotificationData old_data = notification->get_data();
+ notification->update( {old_data.type, old_data.level ,old_data.duration, std::string(), old_data.hypertext} );
+ } else {
+ notification->close();
+ }
+ return;
+ }
+ }
+ */
+}
+void NotificationManager::device_ejected()
+{
+ for (std::unique_ptr& notification : m_pop_notifications) {
+ if (notification->get_type() == NotificationType::ExportFinished && dynamic_cast(notification.get())->m_to_removable)
+ notification->close();
+ }
+}
+
}//namespace GUI
}//namespace Slic3r
diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp
index 49de00a9f4..0550dab9bd 100644
--- a/src/slic3r/GUI/NotificationManager.hpp
+++ b/src/slic3r/GUI/NotificationManager.hpp
@@ -32,7 +32,11 @@ enum class NotificationType
SlicingComplete,
// SlicingNotPossible,
// Notification on end of export to a removable media, with hyperling to eject the external media.
- ExportToRemovableFinished,
+ // Obsolete by ExportFinished
+// ExportToRemovableFinished,
+ // Notification on end of export, with hyperling to see folder and eject if export was to external media.
+ // Own subclass.
+ ExportFinished,
// Works on OSX only.
//FIXME Do we want to have it on Linux and Windows? Is it possible to get the Disconnect event on Windows?
Mouse3dDisconnected,
@@ -115,15 +119,21 @@ public:
// Called when the side bar changes its visibility, as the "slicing complete" notification supplements
// the "slicing info" normally shown at the side bar.
void set_slicing_complete_large(bool large);
+ // Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button
+ void push_exporting_finished_notification(GLCanvas3D& canvas, std::string path, std::string dir_path, bool on_removable);
+ // Close old notification ExportFinished.
+ void new_export_began(bool on_removable);
+ // finds ExportFinished notification and closes it if it was to removable device
+ void device_ejected();
// renders notifications in queue and deletes expired ones
void render_notifications(GLCanvas3D& canvas, float overlay_width);
// finds and closes all notifications of given type
void close_notification_of_type(const NotificationType type);
// Which view is active? Plater or G-code preview? Hide warnings in G-code preview.
void set_in_preview(bool preview);
- // Move to left to avoid colision with variable layer height gizmo
+ // Move to left to avoid colision with variable layer height gizmo.
void set_move_from_overlay(bool move) { m_move_from_overlay = move; }
-
+
private:
// duration 0 means not disapearing
struct NotificationData {
@@ -169,7 +179,7 @@ private:
void close() { m_close_pending = true; }
// data from newer notification of same type
void update(const NotificationData& n);
- bool get_finished() const { return m_finished; }
+ bool get_finished() const { return m_finished || m_close_pending; }
// returns top after movement
float get_top() const { return m_top_y; }
//returns top in actual frame
@@ -187,25 +197,29 @@ private:
protected:
// Call after every size change
void init();
+ // Part of init()
+ virtual void count_spaces();
// Calculetes correct size but not se it in imgui!
virtual void set_next_window_size(ImGuiWrapper& imgui);
virtual void render_text(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
- void render_close_button(ImGuiWrapper& imgui,
+ virtual void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
void render_countdown(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
- void render_hypertext(ImGuiWrapper& imgui,
+ virtual void render_hypertext(ImGuiWrapper& imgui,
const float text_x, const float text_y,
const std::string text,
bool more = false);
+ // Left sign could be error or warning sign
void render_left_sign(ImGuiWrapper& imgui);
- void render_minimize_button(ImGuiWrapper& imgui,
+ virtual void render_minimize_button(ImGuiWrapper& imgui,
const float win_pos_x, const float win_pos_y);
- void on_text_click();
+ // Hypertext action, returns if close notification
+ virtual bool on_text_click();
const NotificationData m_data;
@@ -236,7 +250,9 @@ private:
// Will go to m_finished next render
bool m_close_pending { false };
// variables to count positions correctly
+ // all space without text
float m_window_width_offset;
+ // Space on left side without text
float m_left_indentation;
// Total size of notification window - varies based on monitor
float m_window_height { 56.0f };
@@ -252,6 +268,8 @@ private:
bool m_is_gray { false };
//if multiline = true, notification is showing all lines(>2)
bool m_multiline { false };
+ // True if minimized button is rendered, helps to decide where is area for invisible close button
+ bool m_minimize_b_visible { false };
int m_lines_count{ 1 };
// Target for wxWidgets events sent by clicking on the hyperlink available at some notifications.
wxEvtHandler* m_evt_handler;
@@ -270,7 +288,6 @@ private:
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y)
override;
-
bool m_is_large;
bool m_has_print_info { false };
std::string m_print_info { std::string() };
@@ -284,6 +301,40 @@ private:
int warning_step;
};
+ class ExportFinishedNotification : public PopNotification
+ {
+ public:
+ ExportFinishedNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool to_removable,const std::string& export_path,const std::string& export_dir_path)
+ : PopNotification(n, id_provider, evt_handler)
+ , m_to_removable(to_removable)
+ , m_export_path(export_path)
+ , m_export_dir_path(export_dir_path)
+ {
+ m_multiline = true;
+ }
+ bool m_to_removable;
+ std::string m_export_path;
+ std::string m_export_dir_path;
+ protected:
+ // Reserves space on right for more buttons
+ virtual void count_spaces() override;
+ virtual void render_text(ImGuiWrapper& imgui,
+ const float win_size_x, const float win_size_y,
+ const float win_pos_x, const float win_pos_y) override;
+ // Renders also button to open directory with exported path and eject removable media
+ virtual void render_close_button(ImGuiWrapper& imgui,
+ const float win_size_x, const float win_size_y,
+ const float win_pos_x, const float win_pos_y) override;
+ void render_eject_button(ImGuiWrapper& imgui,
+ const float win_size_x, const float win_size_y,
+ const float win_pos_x, const float win_pos_y);
+ virtual void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override
+ { m_minimize_b_visible = false; }
+ virtual bool on_text_click() override;
+ // local time of last hover for showing tooltip
+ long m_hover_time { 0 };
+ };
+
//pushes notification into the queue of notifications that are rendered
//can be used to create custom notification
bool push_notification_data(const NotificationData& notification_data, GLCanvas3D& canvas, int timestamp);
@@ -314,7 +365,7 @@ private:
//prepared (basic) notifications
const std::vector basic_notifications = {
// {NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")},
- {NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") },
+// {NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") },
{NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") },
// {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") },
// {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") },
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index f819702e42..331f29fa06 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -578,7 +578,7 @@ struct Sidebar::priv
wxButton *btn_export_gcode;
wxButton *btn_reslice;
ScalableButton *btn_send_gcode;
- ScalableButton *btn_eject_device;
+ //ScalableButton *btn_eject_device;
ScalableButton* btn_export_gcode_removable; //exports to removable drives (appears only if removable drive is connected)
bool is_collapsed {false};
@@ -750,13 +750,14 @@ Sidebar::Sidebar(Plater *parent)
(*btn)->Hide();
};
- init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer") + "\tCtrl+Shift+G");
- init_scalable_btn(&p->btn_eject_device, "eject_sd" , _L("Remove device") + "\tCtrl+T");
- init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive") + "\tCtrl+U");
+ init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer ") + GUI::shortkey_ctrl_prefix() + "Shift+G");
+// init_scalable_btn(&p->btn_eject_device, "eject_sd" , _L("Remove device ") + GUI::shortkey_ctrl_prefix() + "T");
+ init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive ") + GUI::shortkey_ctrl_prefix() + "U");
// regular buttons "Slice now" and "Export G-code"
- const int scaled_height = p->btn_eject_device->GetBitmapHeight() + 4;
+// const int scaled_height = p->btn_eject_device->GetBitmapHeight() + 4;
+ const int scaled_height = p->btn_export_gcode_removable->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);
@@ -774,7 +775,7 @@ Sidebar::Sidebar(Plater *parent)
complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND);
complect_btns_sizer->Add(p->btn_send_gcode);
complect_btns_sizer->Add(p->btn_export_gcode_removable);
- complect_btns_sizer->Add(p->btn_eject_device);
+// complect_btns_sizer->Add(p->btn_eject_device);
btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5);
@@ -797,7 +798,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_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
+// p->btn_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
p->btn_export_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(true); });
}
@@ -940,9 +941,9 @@ void Sidebar::msw_rescale()
p->object_info->msw_rescale();
p->btn_send_gcode->msw_rescale();
- p->btn_eject_device->msw_rescale();
+// p->btn_eject_device->msw_rescale();
p->btn_export_gcode_removable->msw_rescale();
- const int scaled_height = p->btn_eject_device->GetBitmap().GetHeight() + 4;
+ const int scaled_height = p->btn_export_gcode_removable->GetBitmap().GetHeight() + 4;
p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height));
p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height));
@@ -965,7 +966,7 @@ void Sidebar::sys_color_changed()
// btn...->msw_rescale() updates icon on button, so use it
p->btn_send_gcode->msw_rescale();
- p->btn_eject_device->msw_rescale();
+// p->btn_eject_device->msw_rescale();
p->btn_export_gcode_removable->msw_rescale();
p->scrolled->Layout();
@@ -1268,7 +1269,7 @@ 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_eject_device->Enable(enable);
+// p->btn_eject_device->Enable(enable);
p->btn_export_gcode_removable->Enable(enable);
}
@@ -1276,8 +1277,8 @@ bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Sh
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_export_removable(bool show) const { return p->btn_export_gcode_removable->Show(show); }
-bool Sidebar::show_eject(bool show) const { return p->btn_eject_device->Show(show); }
-bool Sidebar::get_eject_shown() const { return p->btn_eject_device->IsShown(); }
+//bool Sidebar::show_eject(bool show) const { return p->btn_eject_device->Show(show); }
+//bool Sidebar::get_eject_shown() const { return p->btn_eject_device->IsShown(); }
bool Sidebar::is_multifilament()
{
@@ -1468,6 +1469,13 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
return true;
}
+// State to manage showing after export notifications and device ejecting
+enum ExportingStatus{
+ NOT_EXPORTING,
+ EXPORTING_TO_REMOVABLE,
+ EXPORTING_TO_LOCAL
+};
+
// Plater / private
struct Plater::priv
{
@@ -1770,8 +1778,9 @@ struct Plater::priv
// Caching last value of show_action_buttons parameter for show_action_buttons(), so that a callback which does not know this state will not override it.
mutable bool ready_to_slice = { false };
// Flag indicating that the G-code export targets a removable device, therefore the show_action_buttons() needs to be called at any case when the background processing finishes.
- bool writing_to_removable_device { false };
- bool show_ExportToRemovableFinished_notification { false };
+ ExportingStatus exporting_status { NOT_EXPORTING };
+ std::string last_output_path;
+ std::string last_output_dir_path;
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
bool process_completed_with_error { false };
private:
@@ -2043,9 +2052,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
});
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) {
this->show_action_buttons(this->ready_to_slice);
- if (!this->sidebar->get_eject_shown()) {
- notification_manager->close_notification_of_type(NotificationType::ExportToRemovableFinished);
- }
+ // Close notification ExportingFinished but only if last export was to removable
+ notification_manager->device_ejected();
});
// Start the background thread and register this window as a target for update events.
wxGetApp().removable_drive_manager()->init(this->q);
@@ -2912,6 +2920,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
const wxString invalid_str = _L("Invalid data");
for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport})
sidebar->set_btn_label(btn, invalid_str);
+ process_completed_with_error = true;
}
else
{
@@ -3511,9 +3520,7 @@ void Plater::priv::on_slicing_completed(wxCommandEvent & evt)
void Plater::priv::on_export_began(wxCommandEvent& evt)
{
if (show_warning_dialog)
- warnings_dialog();
- if (this->writing_to_removable_device)
- this->show_ExportToRemovableFinished_notification = true;
+ warnings_dialog();
}
void Plater::priv::on_slicing_began()
{
@@ -3591,10 +3598,14 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
} else
notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D());
this->statusbar()->set_status_text(from_u8(message));
- const wxString invalid_str = _L("Invalid data");
- for (auto btn : { ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport })
- sidebar->set_btn_label(btn, invalid_str);
- process_completed_with_error = true;
+ if (evt.invalidate_plater())
+ {
+ const wxString invalid_str = _L("Invalid data");
+ for (auto btn : { ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport })
+ sidebar->set_btn_label(btn, invalid_str);
+ process_completed_with_error = true;
+ }
+
}
if (evt.cancelled())
this->statusbar()->set_status_text(_L("Cancelled"));
@@ -3629,13 +3640,14 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
show_action_buttons(false);
}
// If writing to removable drive was scheduled, show notification with eject button
- if (this->writing_to_removable_device && this->show_ExportToRemovableFinished_notification) {
+ if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !this->process_completed_with_error) {
show_action_buttons(false);
- notification_manager->push_notification(NotificationType::ExportToRemovableFinished, *q->get_current_canvas3D());
- }
+ notification_manager->push_exporting_finished_notification(*q->get_current_canvas3D(), last_output_path, last_output_dir_path, true);
+ wxGetApp().removable_drive_manager()->set_exporting_finished(true);
+ }else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !this->process_completed_with_error)
+ notification_manager->push_exporting_finished_notification(*q->get_current_canvas3D(), last_output_path, last_output_dir_path, false);
}
- this->show_ExportToRemovableFinished_notification = false;
- this->writing_to_removable_device = false;
+ exporting_status = ExportingStatus::NOT_EXPORTING;
}
void Plater::priv::on_layer_editing_toggled(bool enable)
@@ -4306,8 +4318,8 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
if (sidebar->show_reslice(false) |
sidebar->show_export(true) |
sidebar->show_send(send_gcode_shown) |
- sidebar->show_export_removable(removable_media_status.has_removable_drives) |
- sidebar->show_eject(removable_media_status.has_eject))
+ sidebar->show_export_removable(removable_media_status.has_removable_drives))
+// sidebar->show_eject(removable_media_status.has_eject))
sidebar->Layout();
}
else
@@ -4318,8 +4330,8 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
if (sidebar->show_reslice(ready_to_slice) |
sidebar->show_export(!ready_to_slice) |
sidebar->show_send(send_gcode_shown && !ready_to_slice) |
- sidebar->show_export_removable(!ready_to_slice && removable_media_status.has_removable_drives) |
- sidebar->show_eject(!ready_to_slice && removable_media_status.has_eject))
+ sidebar->show_export_removable(!ready_to_slice && removable_media_status.has_removable_drives))
+// sidebar->show_eject(!ready_to_slice && removable_media_status.has_eject))
sidebar->Layout();
}
}
@@ -4958,7 +4970,7 @@ void Plater::export_gcode(bool prefer_removable)
if (p->model.objects.empty())
return;
- if (p->process_completed_with_error)//here
+ if (p->process_completed_with_error)
return;
// If possible, remove accents from accented latin characters.
@@ -5003,7 +5015,10 @@ void Plater::export_gcode(bool prefer_removable)
if (! output_path.empty()) {
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
- p->writing_to_removable_device = path_on_removable_media;
+ p->notification_manager->new_export_began(path_on_removable_media);
+ p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL;
+ p->last_output_path = output_path.string();
+ p->last_output_dir_path = output_path.parent_path().string();
p->export_gcode(output_path, path_on_removable_media, PrintHostJob());
// Storing a path to AppConfig either as path to removable media or a path to internal media.
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
@@ -5223,6 +5238,10 @@ void Plater::export_toolpaths_to_obj() const
void Plater::reslice()
{
+ // There is "invalid data" button instead "slice now"
+ if (p->process_completed_with_error)
+ return;
+
// Stop arrange and (or) optimize rotation tasks.
this->stop_jobs();
diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp
index d865fe3476..0f6f5255eb 100644
--- a/src/slic3r/GUI/RemovableDriveManager.cpp
+++ b/src/slic3r/GUI/RemovableDriveManager.cpp
@@ -391,7 +391,6 @@ bool RemovableDriveManager::set_and_verify_last_save_path(const std::string &pat
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
-
m_last_save_path = this->get_removable_drive_from_path(path);
m_exporting_finished = false;
return ! m_last_save_path.empty();