From 92f0c01ee3858b4444d8c6304e26aa0432ffaf06 Mon Sep 17 00:00:00 2001 From: bgiot Date: Mon, 22 Jun 2020 16:47:57 +0200 Subject: [PATCH 1/6] Use the correct LIBPNG --- deps/wxWidgets/wxWidgets.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index ee8a22c4f..34103c8ec 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -23,7 +23,7 @@ prusaslicer_add_cmake_project(wxWidgets -DwxUSE_DETECT_SM=OFF -DwxUSE_UNICODE=ON -DwxUSE_OPENGL=ON - -DwxUSE_LIBPNG=sys + -DwxUSE_LIBPNG=builtin -DwxUSE_ZLIB=sys -DwxUSE_REGEX=builtin -DwxUSE_LIBXPM=builtin From 21648c63565287dea03e0f5508ad23701e82bc0d Mon Sep 17 00:00:00 2001 From: bgiot Date: Mon, 6 Jul 2020 12:45:06 +0200 Subject: [PATCH 2/6] Fix macos deps --- deps/deps-macos.cmake | 2 ++ deps/wxWidgets/wxWidgets.cmake | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/deps/deps-macos.cmake b/deps/deps-macos.cmake index ef00b80d5..a71a0ebfc 100644 --- a/deps/deps-macos.cmake +++ b/deps/deps-macos.cmake @@ -9,6 +9,8 @@ set(DEP_CMAKE_OPTS "-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEP_OSX_TARGET}" "-DCMAKE_CXX_FLAGS=${DEP_WERRORS_SDK}" "-DCMAKE_C_FLAGS=${DEP_WERRORS_SDK}" + "-DCMAKE_FIND_FRAMEWORK=LAST" + "-DCMAKE_FIND_APPBUNDLE=LAST" ) include("deps-unix-common.cmake") diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 34103c8ec..ee8a22c4f 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -23,7 +23,7 @@ prusaslicer_add_cmake_project(wxWidgets -DwxUSE_DETECT_SM=OFF -DwxUSE_UNICODE=ON -DwxUSE_OPENGL=ON - -DwxUSE_LIBPNG=builtin + -DwxUSE_LIBPNG=sys -DwxUSE_ZLIB=sys -DwxUSE_REGEX=builtin -DwxUSE_LIBXPM=builtin From f5215cac44b3283baeb86ce075447f8165123394 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 13 Jul 2020 13:16:18 +0200 Subject: [PATCH 3/6] Attempt to fix crash on Mac when rotating an object while layer editing is active --- src/libslic3r/PrintObject.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index cc39cbf0a..d2bdb6d53 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1577,7 +1577,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c bool updated = false; if (layer_height_profile.empty()) { - layer_height_profile = model_object.layer_height_profile; + // use the constructor because the assignement is crashing on ASAN OsX + layer_height_profile = std::vector(model_object.layer_height_profile); +// layer_height_profile = model_object.layer_height_profile; updated = true; } From 746ece4c40dbbc889b9e029f6f39b6c52e7bcbdc Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 14 Jul 2020 11:52:34 +0200 Subject: [PATCH 4/6] Support for collecting warnings from the background processing. Multiple warnigns may be collected per Print / PrintObject milestone and a status update is sent to the UI immediately after a warning is issued. --- src/libslic3r/Print.hpp | 7 ++ src/libslic3r/PrintBase.hpp | 144 ++++++++++++++++++++++++++++++------ src/libslic3r/SLAPrint.hpp | 7 ++ src/slic3r/GUI/Plater.cpp | 21 ++++++ 4 files changed, 158 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 9da85bfba..bf541e122 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -395,6 +395,13 @@ public: const PrintObjectPtrs& objects() const { return m_objects; } PrintObject* get_object(size_t idx) { return m_objects[idx]; } const PrintObject* get_object(size_t idx) const { return m_objects[idx]; } + // PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects + // in the notification center. + const PrintObject* get_object(ObjectID object_id) const { + auto it = std::find_if(m_objects.begin(), m_objects.end(), + [object_id](const PrintObject *obj) { return *static_cast(obj) == object_id; }); + return (it == m_objects.end()) ? nullptr : *it; + } const PrintRegionPtrs& regions() const { return m_regions; } // How many of PrintObject::copies() over all print objects are there? // If zero, then the print is empty and the print shall not be executed. diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 05d884cc8..5e422ca70 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -13,6 +13,7 @@ #endif #include "tbb/mutex.h" +#include "ObjectID.hpp" #include "Model.hpp" #include "PlaceholderParser.hpp" #include "PrintConfig.hpp" @@ -32,6 +33,11 @@ public: DONE, }; + enum class WarningLevel { + NON_CRITICAL, + CRITICAL + }; + typedef size_t TimeStamp; // A new unique timestamp is being assigned to the step every time the step changes its state. @@ -42,6 +48,17 @@ public: TimeStamp timestamp; }; + struct Warning + { + WarningLevel level; + std::string message; + }; + + struct StateWithWarnings : public StateWithTimeStamp + { + std::vector warnings; + }; + protected: //FIXME last timestamp is shared between Print & SLAPrint, // and if multiple Print or SLAPrint instances are executed in parallel, modification of g_last_timestamp @@ -56,12 +73,18 @@ class PrintState : public PrintStateBase public: PrintState() {} - StateWithTimeStamp state_with_timestamp(StepType step, tbb::mutex &mtx) const { + StateWithTimeStamp state_with_timestamp(StepType step, tbb::mutex &mtx) const { tbb::mutex::scoped_lock lock(mtx); StateWithTimeStamp state = m_state[step]; return state; } + StateWithWarnings state_with_warnings(StepType step, tbb::mutex &mtx) const { + tbb::mutex::scoped_lock lock(mtx); + StateWithWarnings state = m_state[step]; + return state; + } + bool is_started(StepType step, tbb::mutex &mtx) const { return this->state_with_timestamp(step, mtx).state == STARTED; } @@ -91,10 +114,26 @@ public: tbb::mutex::scoped_lock lock(mtx); // If canceled, throw before changing the step state. throw_if_canceled(); +#ifndef NDEBUG +// The following test is not necessarily valid after the background processing thread +// is stopped with throw_if_canceled(), as the CanceledException is not being catched +// by the Print or PrintObject to update m_step_active or m_state[...].state. +// This should not be a problem as long as the caller calls set_started() / set_done() / +// active_step_add_warning() consistently. From the robustness point of view it would be +// be better to catch CanceledException and do the updates. From the performance point of view, +// the current implementation is optimal. +// +// assert(m_step_active == -1); +// for (int i = 0; i < int(COUNT); ++ i) +// assert(m_state[i].state != STARTED); +#endif // NDEBUG if (m_state[step].state == DONE) return false; - m_state[step].state = STARTED; - m_state[step].timestamp = ++ g_last_timestamp; + PrintStateBase::StateWithWarnings &state = m_state[step]; + state.state = STARTED; + state.timestamp = ++ g_last_timestamp; + state.warnings.clear(); + m_step_active = static_cast(step); return true; } @@ -105,10 +144,13 @@ public: tbb::mutex::scoped_lock lock(mtx); // If canceled, throw before changing the step state. throw_if_canceled(); - assert(m_state[step].state != DONE); - m_state[step].state = DONE; - m_state[step].timestamp = ++ g_last_timestamp; - return m_state[step].timestamp; + assert(m_state[step].state == STARTED); + assert(m_step_active == static_cast(step)); + PrintStateBase::StateWithWarnings &state = m_state[step]; + state.state = DONE; + state.timestamp = ++ g_last_timestamp; + m_step_active = -1; + return state.timestamp; } // Make the step invalid. @@ -124,13 +166,18 @@ public: printf("Not held!\n"); } #endif - m_state[step].state = INVALID; - m_state[step].timestamp = ++ g_last_timestamp; + PrintStateBase::StateWithWarnings &state = m_state[step]; + state.state = INVALID; + state.timestamp = ++ g_last_timestamp; // Raise the mutex, so that the following cancel() callback could cancel // the background processing. // Internally the cancel() callback shall unlock the PrintBase::m_status_mutex to let - // the working thread to proceed. + // the working thread proceed. cancel(); + // Now the worker thread should be stopped, therefore it cannot write into the warnings field. + // It is safe to clear it. + state.warnings.clear(); + m_step_active = -1; } return invalidated; } @@ -157,6 +204,11 @@ public: // Internally the cancel() callback shall unlock the PrintBase::m_status_mutex to let // the working thread to proceed. cancel(); + // Now the worker thread should be stopped, therefore it cannot write into the warnings field. + // It is safe to clear it. + for (StepTypeIterator it = step_begin; it != step_end; ++ it) + m_state[*it].warnings.clear(); + m_step_active = -1; } return invalidated; } @@ -176,18 +228,37 @@ public: state.timestamp = ++ g_last_timestamp; } } - if (invalidated) + if (invalidated) { cancel(); + // Now the worker thread should be stopped, therefore it cannot write into the warnings field. + // It is safe to clear it. + for (size_t i = 0; i < COUNT; ++ i) + m_state[i].warnings.clear(); + m_step_active = -1; + } return invalidated; } + StepType active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, tbb::mutex &mtx) + { + tbb::mutex::scoped_lock lock(mtx); + assert(m_step_active != -1); + assert(m_state[m_step_active].state == STARTED); + m_state[m_step_active].warnings.emplace_back(PrintStateBase::Warning{ warning_level, message}); + return static_cast(m_step_active); + } + private: - StateWithTimeStamp m_state[COUNT]; + StateWithWarnings m_state[COUNT]; + // Active class StepType or -1 if none is active. + // If the background processing is canceled, m_step_active may not be resetted + // to -1, see the comment in this->set_started(). + int m_step_active = -1; }; class PrintBase; -class PrintObjectBase +class PrintObjectBase : public ObjectID { public: const ModelObject* model_object() const { return m_model_object; } @@ -214,7 +285,7 @@ protected: * The PrintBase class will abstract this flow for different technologies. * */ -class PrintBase +class PrintBase : public ObjectID { public: PrintBase() : m_placeholder_parser(&m_full_print_config) { this->restart(); } @@ -264,17 +335,29 @@ public: struct SlicingStatus { SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {} - int percent; + SlicingStatus(const PrintBase &print, int warning_step) : + flags(UPDATE_PRINT_STEP_WARNINGS), warning_object_id(print), warning_step(warning_step) {} + SlicingStatus(const PrintObjectBase &print_object, int warning_step) : + flags(UPDATE_PRINT_OBJECT_STEP_WARNINGS), warning_object_id(print_object), warning_step(warning_step) {} + int percent { -1 }; std::string text; // Bitmap of flags. enum FlagBits { - DEFAULT = 0, - RELOAD_SCENE = 1 << 1, - RELOAD_SLA_SUPPORT_POINTS = 1 << 2, - RELOAD_SLA_PREVIEW = 1 << 3, + DEFAULT = 0, + RELOAD_SCENE = 1 << 1, + RELOAD_SLA_SUPPORT_POINTS = 1 << 2, + RELOAD_SLA_PREVIEW = 1 << 3, + // UPDATE_PRINT_STEP_WARNINGS is mutually exclusive with UPDATE_PRINT_OBJECT_STEP_WARNINGS. + UPDATE_PRINT_STEP_WARNINGS = 1 << 4, + UPDATE_PRINT_OBJECT_STEP_WARNINGS = 1 << 5 }; // Bitmap of FlagBits unsigned int flags; + // set to an ObjectID of a Print or a PrintObject based on flags + // (whether UPDATE_PRINT_STEP_WARNINGS or UPDATE_PRINT_OBJECT_STEP_WARNINGS is set). + ObjectID warning_object_id; + // For which Print or PrintObject step a new warning is beeing issued? + int warning_step { -1 }; }; typedef std::function status_callback_type; // Default status console print out in the form of percent => message. @@ -343,11 +426,12 @@ protected: DynamicPrintConfig m_full_print_config; PlaceholderParser m_placeholder_parser; -private: - tbb::atomic m_cancel_status; // Callback to be evoked regularly to update state of the UI thread. status_callback_type m_status_callback; +private: + tbb::atomic m_cancel_status; + // Callback to be evoked to stop the background processing before a state is updated. cancel_callback_type m_cancel_callback = [](){}; @@ -363,6 +447,7 @@ class PrintBaseWithState : public PrintBase public: bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step, this->state_mutex()); } PrintStateBase::StateWithTimeStamp step_state_with_timestamp(PrintStepEnum step) const { return m_state.state_with_timestamp(step, this->state_mutex()); } + PrintStateBase::StateWithWarnings step_state_with_warnings(PrintStepEnum step) const { return m_state.state_with_warnings(step, this->state_mutex()); } protected: bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); } @@ -380,6 +465,14 @@ protected: bool is_step_started_unguarded(PrintStepEnum step) const { return m_state.is_started_unguarded(step); } bool is_step_done_unguarded(PrintStepEnum step) const { return m_state.is_done_unguarded(step); } + // Add a slicing warning to the active Print step and send a status notification. + // This method could be called multiple times between this->set_started() and this->set_done(). + void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message) { + PrintStepEnum active_step = m_state.active_step_add_warning(warning_level, message, this->state_mutex()); + if (m_status_callback) m_status_callback(SlicingStatus(*this, active_step)); + else printf("print warning: %s\n", message.c_str()); + } + private: PrintState m_state; }; @@ -394,6 +487,7 @@ public: typedef PrintState PrintObjectState; bool is_step_done(PrintObjectStepEnum step) const { return m_state.is_done(step, PrintObjectBase::state_mutex(m_print)); } PrintStateBase::StateWithTimeStamp step_state_with_timestamp(PrintObjectStepEnum step) const { return m_state.state_with_timestamp(step, PrintObjectBase::state_mutex(m_print)); } + PrintStateBase::StateWithWarnings step_state_with_warnings(PrintObjectStepEnum step) const { return m_state.state_with_warnings(step, PrintObjectBase::state_mutex(m_print)); } protected: PrintObjectBaseWithState(PrintType *print, ModelObject *model_object) : PrintObjectBase(model_object), m_print(print) {} @@ -416,6 +510,14 @@ protected: bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); } bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); } + // Add a slicing warning to the active PrintObject step and send a status notification. + // This method could be called multiple times between this->set_started() and this->set_done(). + void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message) { + PrintObjectStepEnum active_step = m_state.active_step_add_warning(warning_level, message, PrintObjectBase::state_mutex(m_print)); + if (m_print.m_status_callback) m_print.m_status_callback(SlicingStatus(*this, active_step)); + else printf("print object warning: %s\n", message.c_str()); + } + protected: // If the background processing stop was requested, throw CanceledException. // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index a27207565..573fc2b0c 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -429,6 +429,13 @@ public: bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } const PrintObjects& objects() const { return m_objects; } + // PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects + // in the notification center. + const SLAPrintObject* get_object(ObjectID object_id) const { + auto it = std::find_if(m_objects.begin(), m_objects.end(), + [object_id](const SLAPrintObject *obj) { return *static_cast(obj) == object_id; }); + return (it == m_objects.end()) ? nullptr : *it; + } const SLAPrintConfig& print_config() const { return m_print_config; } const SLAPrinterConfig& printer_config() const { return m_printer_config; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f1156271c..ec13610b8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3413,6 +3413,27 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); } + + if (evt.status.flags & (PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS | PrintBase::SlicingStatus::UPDATE_PRINT_OBJECT_STEP_WARNINGS)) { + // Update notification center with warnings of object_id and its warning_step. + ObjectID object_id = evt.status.warning_object_id; + int warning_step = evt.status.warning_step; + PrintStateBase::StateWithWarnings state; + if (evt.status.flags & PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) { + state = this->printer_technology == ptFFF ? + this->fff_print.step_state_with_warnings(static_cast(warning_step)) : + this->sla_print.step_state_with_warnings(static_cast(warning_step)); + } else if (this->printer_technology == ptFFF) { + const PrintObject *print_object = this->fff_print.get_object(object_id); + if (print_object) + state = print_object->step_state_with_warnings(static_cast(warning_step)); + } else { + const SLAPrintObject *print_object = this->sla_print.get_object(object_id); + if (print_object) + state = print_object->step_state_with_warnings(static_cast(warning_step)); + } + // Now process state.warnings. + } } void Plater::priv::on_slicing_completed(wxCommandEvent &) From f64da8e6ccde6e98f73f78aa3acd1557601328c6 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 15 Jul 2020 18:03:39 +0200 Subject: [PATCH 5/6] Update of back-end warnings: Back-end warnings contain two new members: "current" and "message_id". A warning is set to "not current" if its milestone is invalidated. --- src/libslic3r/PrintBase.cpp | 13 ++++ src/libslic3r/PrintBase.hpp | 116 ++++++++++++++++++++++++++++-------- 2 files changed, 103 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index 81affe04d..14339f3c6 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -88,6 +88,14 @@ std::string PrintBase::output_filepath(const std::string &path, const std::strin return path; } +void PrintBase::status_update_warnings(ObjectID object_id, int step, PrintStateBase::WarningLevel /* warning_level */, const std::string &message) +{ + if (this->m_status_callback) + m_status_callback(SlicingStatus(*this, step)); + else if (! message.empty()) + printf("%s warning: %s\n", (object_id == ObjectID(*this)) ? "print" : "print object", message.c_str()); +} + tbb::mutex& PrintObjectBase::state_mutex(PrintBase *print) { return print->state_mutex(); @@ -98,4 +106,9 @@ std::function PrintObjectBase::cancel_callback(PrintBase *print) return print->cancel_callback(); } +void PrintObjectBase::status_update_warnings(PrintBase *print, int step, PrintStateBase::WarningLevel warning_level, const std::string &message) +{ + print->status_update_warnings(*this, step, warning_level, message); +} + } // namespace Slic3r diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 5e422ca70..65f1764e5 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -50,12 +50,23 @@ public: struct Warning { + // Critical warnings will be displayed on G-code export in a modal dialog, so that the user cannot miss them. WarningLevel level; + // If the warning is not current, then it is in an unknown state. It may or may not be valid. + // A current warning will become non-current if its milestone gets invalidated. + // A non-current warning will either become current or it will be removed at the end of a milestone. + bool current; + // Message to be shown to the user, UTF8, localized. std::string message; + // If message_id == 0, then the message is expected to identify the warning uniquely. + // Otherwise message_id identifies the message. For example, if the message contains a varying number, then + // it cannot itself identify the message type. + int message_id; }; struct StateWithWarnings : public StateWithTimeStamp { + void mark_warnings_non_current() { for (auto &w : warnings) w.current = false; } std::vector warnings; }; @@ -132,15 +143,18 @@ public: PrintStateBase::StateWithWarnings &state = m_state[step]; state.state = STARTED; state.timestamp = ++ g_last_timestamp; - state.warnings.clear(); + state.mark_warnings_non_current(); m_step_active = static_cast(step); return true; } // Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being // modified by the UI thread. + // Return value: + // Timestamp when this stepentered the DONE state. + // bool indicates whether the UI has to update the slicing warnings of this step or not. template - TimeStamp set_done(StepType step, tbb::mutex &mtx, ThrowIfCanceled throw_if_canceled) { + std::pair set_done(StepType step, tbb::mutex &mtx, ThrowIfCanceled throw_if_canceled) { tbb::mutex::scoped_lock lock(mtx); // If canceled, throw before changing the step state. throw_if_canceled(); @@ -150,7 +164,14 @@ public: state.state = DONE; state.timestamp = ++ g_last_timestamp; m_step_active = -1; - return state.timestamp; + // Remove all non-current warnings. + auto it = std::remove_if(state.warnings.begin(), state.warnings.end(), [](const auto &w) { return ! w.current; }); + bool update_warning_ui = false; + if (it != state.warnings.end()) { + state.warnings.erase(it, state.warnings.end()); + update_warning_ui = true; + } + return std::make_pair(state.timestamp, update_warning_ui); } // Make the step invalid. @@ -175,8 +196,8 @@ public: // the working thread proceed. cancel(); // Now the worker thread should be stopped, therefore it cannot write into the warnings field. - // It is safe to clear it. - state.warnings.clear(); + // It is safe to modify it. + state.mark_warnings_non_current(); m_step_active = -1; } return invalidated; @@ -205,9 +226,9 @@ public: // the working thread to proceed. cancel(); // Now the worker thread should be stopped, therefore it cannot write into the warnings field. - // It is safe to clear it. + // It is safe to modify the warnings. for (StepTypeIterator it = step_begin; it != step_end; ++ it) - m_state[*it].warnings.clear(); + m_state[*it].mark_warnings_non_current(); m_step_active = -1; } return invalidated; @@ -231,21 +252,46 @@ public: if (invalidated) { cancel(); // Now the worker thread should be stopped, therefore it cannot write into the warnings field. - // It is safe to clear it. + // It is safe to modify the warnings. for (size_t i = 0; i < COUNT; ++ i) - m_state[i].warnings.clear(); + m_state[i].mark_warnings_non_current(); m_step_active = -1; } return invalidated; } - StepType active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, tbb::mutex &mtx) + // Update list of warnings of the current milestone with a new warning. + // The warning may already exist in the list, marked as current or not current. + // If it already exists, mark it as current. + // Return value: + // Current milestone (StepType). + // bool indicates whether the UI has to be updated or not. + std::pair active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id, tbb::mutex &mtx) { tbb::mutex::scoped_lock lock(mtx); assert(m_step_active != -1); - assert(m_state[m_step_active].state == STARTED); - m_state[m_step_active].warnings.emplace_back(PrintStateBase::Warning{ warning_level, message}); - return static_cast(m_step_active); + StateWithWarnings &state = m_state[m_step_active]; + assert(state.state == STARTED); + std::pair retval(static_cast(m_step_active), true); + // Does a warning of the same level and message or message_id exist already? + auto it = (message_id == 0) ? + std::find_if(state.warnings.begin(), state.warnings.end(), [&message](const auto &w) { return w.message_id == 0 && w.message == message; }) : + std::find_if(state.warnings.begin(), state.warnings.end(), [message_id](const auto& w) { return w.message_id == message_id; }); + if (it == state.warnings.end()) + // No, create a new warning and update UI. + state.warnings.emplace_back(PrintStateBase::Warning{ warning_level, true, message, message_id }); + else if (it->message != message || it->level != warning_level) { + // Yes, however it needs an update. + it->message = message; + it->level = warning_level; + it->current = true; + } else if (it->current) + // Yes, and it is current. Don't update UI. + retval.second = false; + else + // Yes, but it is not current. Mark it as current. + it->current = true; + return retval; } private: @@ -268,8 +314,12 @@ protected: PrintObjectBase(ModelObject *model_object) : m_model_object(model_object) {} virtual ~PrintObjectBase() {} // Declared here to allow access from PrintBase through friendship. - static tbb::mutex& state_mutex(PrintBase *print); - static std::function cancel_callback(PrintBase *print); + static tbb::mutex& state_mutex(PrintBase *print); + static std::function cancel_callback(PrintBase *print); + // Notify UI about a new warning of a milestone "step" on this PrintObjectBase. + // The UI will be notified by calling a status callback registered on print. + // If no status callback is registered, the message is printed to console. + void status_update_warnings(PrintBase *print, int step, PrintStateBase::WarningLevel warning_level, const std::string &message); ModelObject *m_model_object; }; @@ -412,6 +462,10 @@ protected: tbb::mutex& state_mutex() const { return m_state_mutex; } std::function cancel_callback() { return m_cancel_callback; } void call_cancel_callback() { m_cancel_callback(); } + // Notify UI about a new warning of a milestone "step" on this PrintBase. + // The UI will be notified by calling a status callback. + // If no status callback is registered, the message is printed to console. + void status_update_warnings(ObjectID object_id, int step, PrintStateBase::WarningLevel warning_level, const std::string &message); // If the background processing stop was requested, throw CanceledException. // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. @@ -451,7 +505,12 @@ public: protected: bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); } - PrintStateBase::TimeStamp set_done(PrintStepEnum step) { return m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); } + PrintStateBase::TimeStamp set_done(PrintStepEnum step) { + std::pair status = m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); + if (status.second) + this->status_update_warnings(*this, static_cast(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string()); + return status.first; + } bool invalidate_step(PrintStepEnum step) { return m_state.invalidate(step, this->cancel_callback()); } template @@ -467,10 +526,11 @@ protected: // Add a slicing warning to the active Print step and send a status notification. // This method could be called multiple times between this->set_started() and this->set_done(). - void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message) { - PrintStepEnum active_step = m_state.active_step_add_warning(warning_level, message, this->state_mutex()); - if (m_status_callback) m_status_callback(SlicingStatus(*this, active_step)); - else printf("print warning: %s\n", message.c_str()); + void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) { + std::pair active_step = m_state.active_step_add_warning(warning_level, message, message_id, this->state_mutex()); + if (active_step.second) + // Update UI. + this->status_update_warnings(*this, static_cast(active_step.first), warning_level, message); } private: @@ -494,8 +554,12 @@ protected: bool set_started(PrintObjectStepEnum step) { return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); } - PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step) - { return m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); } + PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step) { + std::pair status = m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); + if (status.second) + this->status_update_warnings(m_print, static_cast(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string()); + return status.first; + } bool invalidate_step(PrintObjectStepEnum step) { return m_state.invalidate(step, PrintObjectBase::cancel_callback(m_print)); } @@ -512,10 +576,10 @@ protected: // Add a slicing warning to the active PrintObject step and send a status notification. // This method could be called multiple times between this->set_started() and this->set_done(). - void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message) { - PrintObjectStepEnum active_step = m_state.active_step_add_warning(warning_level, message, PrintObjectBase::state_mutex(m_print)); - if (m_print.m_status_callback) m_print.m_status_callback(SlicingStatus(*this, active_step)); - else printf("print object warning: %s\n", message.c_str()); + void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) { + std::pair active_step = m_state.active_step_add_warning(warning_level, message, message_id, PrintObjectBase::state_mutex(m_print)); + if (active_step.second) + this->status_update_warnings(m_print, static_cast(active_step.first), warning_level, message); } protected: From ba0146746d88db8f4fff69a24c9f785c06c18005 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 15 Jul 2020 18:13:11 +0200 Subject: [PATCH 6/6] Fix of previous commit. --- src/libslic3r/PrintBase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 65f1764e5..d7f3483e8 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -527,7 +527,7 @@ protected: // Add a slicing warning to the active Print step and send a status notification. // This method could be called multiple times between this->set_started() and this->set_done(). void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) { - std::pair active_step = m_state.active_step_add_warning(warning_level, message, message_id, this->state_mutex()); + std::pair active_step = m_state.active_step_add_warning(warning_level, message, message_id, this->state_mutex()); if (active_step.second) // Update UI. this->status_update_warnings(*this, static_cast(active_step.first), warning_level, message); @@ -577,7 +577,7 @@ protected: // Add a slicing warning to the active PrintObject step and send a status notification. // This method could be called multiple times between this->set_started() and this->set_done(). void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) { - std::pair active_step = m_state.active_step_add_warning(warning_level, message, message_id, PrintObjectBase::state_mutex(m_print)); + std::pair active_step = m_state.active_step_add_warning(warning_level, message, message_id, PrintObjectBase::state_mutex(m_print)); if (active_step.second) this->status_update_warnings(m_print, static_cast(active_step.first), warning_level, message); }