From 447f4b83030815f71d74242789066faa13593909 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 16:48:56 +0200 Subject: [PATCH] Polishing of NotificationManager: Fixed pairing of PrintObjects with slicing warning notifications. Removed or commented out dead code. Added documentation. --- src/libslic3r/Print.cpp | 10 +++++ src/libslic3r/Print.hpp | 2 + src/libslic3r/PrintBase.hpp | 2 + src/libslic3r/SLAPrint.cpp | 10 +++++ src/libslic3r/SLAPrint.hpp | 2 + src/slic3r/GUI/GLCanvas3D.cpp | 11 +++--- src/slic3r/GUI/NotificationManager.cpp | 52 ++++++++++---------------- src/slic3r/GUI/NotificationManager.hpp | 44 +++++++++++++--------- src/slic3r/GUI/Plater.cpp | 24 ++++++------ 9 files changed, 89 insertions(+), 68 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 01e46d227..3061693a7 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -577,6 +577,16 @@ void Print::config_diffs( } } +std::vector Print::print_object_ids() const +{ + std::vector out; + // Reserve one more for the caller to append the ID of the Print itself. + out.reserve(m_objects.size() + 1); + for (const PrintObject *print_object : m_objects) + out.emplace_back(print_object->id()); + return out; +} + Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config) { #ifdef _DEBUG diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a389ef00d..29cdc7249 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -370,6 +370,8 @@ public: // a cancellation callback is executed to stop the background processing before the operation. void clear() override; bool empty() const override { return m_objects.empty(); } + // List of existing PrintObject IDs, to remove notifications for non-existent IDs. + std::vector print_object_ids() const override; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 66851f16e..bfbabd06b 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -348,6 +348,8 @@ public: // The Print is empty either after clear() or after apply() over an empty model, // or after apply() over a model, where no object is printable (all outside the print volume). virtual bool empty() const = 0; + // List of existing PrintObject IDs, to remove notifications for non-existent IDs. + virtual std::vector print_object_ids() const = 0; // Validate the print, return empty string if valid, return error if process() cannot (or should not) be started. virtual std::string validate() const { return std::string(); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index a2d2ff620..54cf55cab 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -175,6 +175,16 @@ static std::vector sla_instances(const ModelObject &mo return instances; } +std::vector SLAPrint::print_object_ids() const +{ + std::vector out; + // Reserve one more for the caller to append the ID of the Print itself. + out.reserve(m_objects.size() + 1); + for (const SLAPrintObject *print_object : m_objects) + out.emplace_back(print_object->id()); + return out; +} + SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig config) { #ifdef _DEBUG diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 5ca1b2b8e..a4305e0c3 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -420,6 +420,8 @@ public: void clear() override; bool empty() const override { return m_objects.empty(); } + // List of existing PrintObject IDs, to remove notifications for non-existent IDs. + std::vector print_object_ids() const; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; void set_task(const TaskParams ¶ms) override; void process() override; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e87fa383d..18b1aaa2c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -640,16 +640,17 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool error = true; break; } - if(state) { + auto ¬ification_manager = *wxGetApp().plater()->get_notification_manager(); + if (state) { if(error) - wxGetApp().plater()->get_notification_manager()->push_plater_error_notification(text,*(wxGetApp().plater()->get_current_canvas3D())); + notification_manager.push_plater_error_notification(text,*(wxGetApp().plater()->get_current_canvas3D())); else - wxGetApp().plater()->get_notification_manager()->push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D())); + notification_manager.push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D())); } else { if (error) - wxGetApp().plater()->get_notification_manager()->close_plater_error_notification(text); + notification_manager.close_plater_error_notification(text); else - wxGetApp().plater()->get_notification_manager()->close_plater_warning_notification(text); + notification_manager.close_plater_warning_notification(text); } /* diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index a11e4c188..922f5f91f 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -625,7 +625,7 @@ void NotificationManager::SlicingCompleteLargeNotification::render_text(ImGuiWra } } -void NotificationManager::SlicingCompleteLargeNotification::set_print_info(std::string info) +void NotificationManager::SlicingCompleteLargeNotification::set_print_info(const std::string &info) { m_print_info = info; m_has_print_info = true; @@ -679,13 +679,13 @@ void NotificationManager::push_slicing_error_notification(const std::string& tex push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, canvas, 0); close_notification_of_type(NotificationType::SlicingComplete); } -void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, size_t oid, int warning_step) +void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, ObjectID oid, int warning_step) { NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }; auto notification = std::make_unique(data, m_id_provider, m_evt_handler); - notification->set_object_id(oid); - notification->set_warning_step(warning_step); + notification->object_id = oid; + notification->warning_step = warning_step; if (push_notification_data(std::move(notification), canvas, 0)) { notification->set_gray(gray); } @@ -732,6 +732,7 @@ void NotificationManager::set_all_slicing_warnings_gray(bool g) } } } +/* void NotificationManager::set_slicing_warning_gray(const std::string& text, bool g) { for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -740,6 +741,7 @@ void NotificationManager::set_slicing_warning_gray(const std::string& text, bool } } } +*/ void NotificationManager::close_slicing_errors_and_warnings() { for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -752,7 +754,7 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, { std::string hypertext; int time = 10; - if (has_error_notification()) + if (has_slicing_error_notification()) return; if (large) { hypertext = _u8L("Export G-Code."); @@ -762,7 +764,7 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, large), canvas, timestamp); } -void NotificationManager::set_slicing_complete_print_time(std::string info) +void NotificationManager::set_slicing_complete_print_time(const std::string &info) { for (std::unique_ptr ¬ification : m_pop_notifications) { if (notification->get_type() == NotificationType::SlicingComplete) { @@ -788,22 +790,14 @@ void NotificationManager::close_notification_of_type(const NotificationType type } } } -void NotificationManager::compare_warning_oids(const std::vector& living_oids) +void NotificationManager::remove_slicing_warnings_of_released_objects(const std::vector& living_oids) { - for (std::unique_ptr ¬ification : m_pop_notifications) { + for (std::unique_ptr ¬ification : m_pop_notifications) if (notification->get_type() == NotificationType::SlicingWarning) { - auto w = dynamic_cast(notification.get()); - bool found = false; - for (size_t oid : living_oids) { - if (w->get_object_id() == oid) { - found = true; - break; - } - } - if (!found) + if (! std::binary_search(living_oids.begin(), living_oids.end(), + static_cast(notification.get())->object_id)) notification->close(); } - } } bool NotificationManager::push_notification_data(const NotificationData ¬ification_data, GLCanvas3D& canvas, int timestamp) { @@ -839,7 +833,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay sort_notifications(); // iterate thru notifications and render them / erease them for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { - if ((*it)->get_finished()) { + if (! (*it)->get_finished()) { it = m_pop_notifications.erase(it); } else { (*it)->set_paused(m_hovered); @@ -885,7 +879,8 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay void NotificationManager::sort_notifications() { - std::sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](const std::unique_ptr &n1, const std::unique_ptr &n2) { + // Stable sorting, so that the order of equal ranges is stable. + std::stable_sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](const std::unique_ptr &n1, const std::unique_ptr &n2) { int n1l = (int)n1->get_data().level; int n2l = (int)n2->get_data().level; if (n1l == n2l && n1->get_is_gray() && !n2->get_is_gray()) @@ -907,7 +902,7 @@ bool NotificationManager::find_older(NotificationManager::PopNotification* notif auto w1 = dynamic_cast(notification); auto w2 = dynamic_cast(it->get()); if (w1 != nullptr && w2 != nullptr) { - if (!(*it)->compare_text(text) || w1->get_object_id() != w2->get_object_id()) { + if (!(*it)->compare_text(text) || w1->object_id != w2->object_id) { continue; } } else { @@ -931,18 +926,11 @@ void NotificationManager::set_in_preview(bool preview) notification->hide(preview); } } -bool NotificationManager::has_error_notification() +bool NotificationManager::has_slicing_error_notification() { - for (std::unique_ptr ¬ification : m_pop_notifications) { - if (notification->get_data().level == NotificationLevel::ErrorNotification) - return true; - } - return false; -} - -void NotificationManager::dpi_changed() -{ - + return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) { + return n->get_type() == NotificationType::SlicingError; + }); } }//namespace GUI diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 2b51c720a..ab3d4a447 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -4,6 +4,8 @@ #include "Event.hpp" #include "I18N.hpp" +#include + #include #include #include @@ -78,30 +80,37 @@ public: // creates Slicing Error notification with custom text void push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas); // creates Slicing Warning notification with custom text - void push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, size_t oid, int warning_step); + void push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, ObjectID oid, int warning_step); // marks slicing errors as gray void set_all_slicing_errors_gray(bool g); // marks slicing warings as gray void set_all_slicing_warnings_gray(bool g); - void set_slicing_warning_gray(const std::string& text, bool g); - // imidietly stops showing slicing errors +// void set_slicing_warning_gray(const std::string& text, bool g); + // immediately stops showing slicing errors void close_slicing_errors_and_warnings(); - void compare_warning_oids(const std::vector& living_oids); + // Release those slicing warnings, which refer to an ObjectID, which is not in the list. + // living_oids is expected to be sorted. + void remove_slicing_warnings_of_released_objects(const std::vector& living_oids); + // Object partially outside of the printer working space, cannot print. void push_plater_error_notification(const std::string& text, GLCanvas3D& canvas); + // Object fully out of the printer working space and such. void push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas); - // Closes error or warning of same text + // Closes error or warning of the same text void close_plater_error_notification(const std::string& text); void close_plater_warning_notification(const std::string& text); // creates special notification slicing complete // if large = true prints printing time and export button void push_slicing_complete_notification(GLCanvas3D& canvas, int timestamp, bool large); - void set_slicing_complete_print_time(std::string info); + // Add a print time estimate to an existing SlicingComplete notification. + void set_slicing_complete_print_time(const std::string &info); + // 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); // renders notifications in queue and deletes expired ones void render_notifications(GLCanvas3D& canvas, float overlay_width, float slope_width); // finds and closes all notifications of given type void close_notification_of_type(const NotificationType type); - void dpi_changed(); + // 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 void set_move_from_overlay(bool move) { m_move_from_overlay = move; } @@ -113,8 +122,8 @@ private: NotificationLevel level; const int duration; const std::string text1; - const std::string hypertext = std::string(); - const std::string text2 = std::string(); + const std::string hypertext; + const std::string text2; }; // Cache of IDs to identify and reuse ImGUI windows. @@ -190,6 +199,7 @@ private: const NotificationData m_data; + // For reusing ImGUI windows. NotificationIDProvider &m_id_provider; int m_id { 0 }; bool m_initialized { false }; @@ -233,6 +243,7 @@ private: //if multiline = true, notification is showing all lines(>2) bool m_multiline { false }; int m_lines_count{ 1 }; + // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. wxEvtHandler* m_evt_handler; }; @@ -243,7 +254,7 @@ private: void set_large(bool l); bool get_large() { return m_is_large; } - void set_print_info(std::string info); + void set_print_info(const std::string &info); protected: virtual void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, @@ -259,13 +270,8 @@ private: { public: SlicingWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {} - void set_object_id(size_t id) { object_id = id; } - const size_t get_object_id() { return object_id; } - void set_warning_step(int ws) { warning_step = ws; } - const int get_warning_step() { return warning_step; } - protected: - size_t object_id; - int warning_step; + ObjectID object_id; + int warning_step; }; //pushes notification into the queue of notifications that are rendered @@ -274,8 +280,10 @@ private: bool push_notification_data(std::unique_ptr notification, GLCanvas3D& canvas, int timestamp); //finds older notification of same type and moves it to the end of queue. returns true if found bool find_older(NotificationManager::PopNotification* notification); + // Put the more important notifications to the bottom of the list. void sort_notifications(); - bool has_error_notification(); + // If there is some error notification active, then the "Export G-code" notification after the slicing is finished is suppressed. + bool has_slicing_error_notification(); // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. wxEvtHandler* m_evt_handler; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f3e6fdd37..902adaacb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1714,7 +1714,8 @@ struct Plater::priv void clear_warnings(); void add_warning(const Slic3r::PrintStateBase::Warning &warning, size_t oid); - void actualizate_warnings(const Model& model, size_t print_oid); + // Update notification manager with the current state of warnings produced by the background process (slicing). + void actualize_slicing_warnings(const PrintBase &print); // Displays dialog window with list of warnings. // Returns true if user clicks OK. // Returns true if current_warnings vector is empty without showning the dialog @@ -2885,8 +2886,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool //actualizate warnings if (invalidated != Print::APPLY_STATUS_UNCHANGED) { - actualizate_warnings(this->q->model(), this->background_process.current_print()->id().id); - notification_manager->set_all_slicing_warnings_gray(true); + actualize_slicing_warnings(*this->background_process.current_print()); show_warning_dialog = false; process_completed_with_error = false; } @@ -3474,7 +3474,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // Now process state.warnings. for (auto const& warning : state.warnings) { if (warning.current) { - notification_manager->push_slicing_warning_notification(warning.message, false, *q->get_current_canvas3D(), object_id.id, warning_step); + notification_manager->push_slicing_warning_notification(warning.message, false, *q->get_current_canvas3D(), object_id, warning_step); add_warning(warning, object_id.id); } } @@ -3520,19 +3520,17 @@ void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, s } current_warnings.emplace_back(std::pair(warning, oid)); } -void Plater::priv::actualizate_warnings(const Model& model, size_t print_oid) +void Plater::priv::actualize_slicing_warnings(const PrintBase &print) { - if (model.objects.size() == 0) { + std::vector ids = print.print_object_ids(); + if (ids.empty()) { clear_warnings(); return; } - std::vector living_oids; - living_oids.push_back(model.id().id); - living_oids.push_back(print_oid); - for (auto it = model.objects.begin(); it != model.objects.end(); ++it) { - living_oids.push_back((*it)->id().id); - } - notification_manager->compare_warning_oids(living_oids); + ids.emplace_back(print.id()); + std::sort(ids.begin(), ids.end()); + notification_manager->remove_slicing_warnings_of_released_objects(ids); + notification_manager->set_all_slicing_warnings_gray(true); } void Plater::priv::clear_warnings() {