From abd5a9a46e16bab66988bf338516b1e0d1f5b4e8 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 26 Feb 2021 08:23:37 +0100 Subject: [PATCH] Add a notification when custom support enforcers are not used due to supports being off It is now emitted from Print::validate and has a hyperlink to enable supports --- src/libslic3r/Print.cpp | 19 ++++++++- src/libslic3r/Print.hpp | 2 +- src/libslic3r/PrintBase.hpp | 2 +- src/libslic3r/PrintObject.cpp | 18 +++++++++ src/libslic3r/SLAPrint.cpp | 2 +- src/libslic3r/SLAPrint.hpp | 2 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 4 +- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 2 +- src/slic3r/GUI/NotificationManager.hpp | 4 +- src/slic3r/GUI/Plater.cpp | 45 ++++++++++++++++++++- 10 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 643cc9a97..89a8dc77b 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1245,7 +1245,7 @@ static inline bool sequential_print_vertical_clearance_valid(const Print &print) } // Precondition: Print::validate() requires the Print::apply() to be called its invocation. -std::string Print::validate() const +std::string Print::validate(std::string* warning) const { if (m_objects.empty()) return L("All objects are outside of the print volume."); @@ -1440,7 +1440,22 @@ std::string Print::validate() const } } } - + + // Do we have custom support data that would not be used? + // Notify the user in that case. + if (! object->has_support() && warning) { + for (const ModelVolume* mv : object->model_object()->volumes) { + bool has_enforcers = mv->is_support_enforcer() + || (mv->is_model_part() + && ! mv->supported_facets.empty() + && ! mv->supported_facets.get_facets(*mv, EnforcerBlockerType::ENFORCER).indices.empty()); + if (has_enforcers) { + *warning = "_SUPPORTS_OFF"; + break; + } + } + } + // validate first_layer_height double first_layer_height = object->config().get_abs_value("first_layer_height"); double first_layer_min_nozzle_diameter; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index e8e81a529..9f22ddf13 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -444,7 +444,7 @@ public: bool has_brim() const; // Returns an empty string if valid, otherwise returns an error message. - std::string validate() const override; + std::string validate(std::string* warning = nullptr) const override; double skirt_first_layer_height() const; Flow brim_flow() const; Flow skirt_flow() const; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 2aff13ae9..e0aa56ba5 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -366,7 +366,7 @@ public: 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(); } + virtual std::string validate(std::string* warning = nullptr) const { return std::string(); } enum ApplyStatus { // No change after the Print::apply() call. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index c963418c3..52bdc87e7 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -430,6 +430,24 @@ void PrintObject::generate_support_material() if (layer->empty()) throw Slic3r::SlicingError("Levitating objects cannot be printed without supports."); #endif + + // Do we have custom support data that would not be used? + // Notify the user in that case. + if (! this->has_support()) { + for (const ModelVolume* mv : this->model_object()->volumes) { + bool has_enforcers = mv->is_support_enforcer() + || (mv->is_model_part() + && ! mv->supported_facets.empty() + && ! mv->supported_facets.get_facets(*mv, EnforcerBlockerType::ENFORCER).indices.empty()); + if (has_enforcers) { + this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, + L("An object has custom support enforcers which will not be used " + "because supports are off. Consider turning them on.") + "\n" + + (L("Object name")) + ": " + this->model_object()->name); + break; + } + } + } } this->set_done(posSupportMaterial); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 65fac73f3..16b068cb9 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -617,7 +617,7 @@ std::string SLAPrint::output_filename(const std::string &filename_base) const return this->PrintBase::output_filename(m_print_config.output_filename_format.value, ".sl1", filename_base, &config); } -std::string SLAPrint::validate() const +std::string SLAPrint::validate(std::string*) const { for(SLAPrintObject * po : m_objects) { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 742670e2c..bed66ab4f 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -458,7 +458,7 @@ public: const SLAPrintStatistics& print_statistics() const { return m_print_statistics; } - std::string validate() const override; + std::string validate(std::string* warning = nullptr) const override; // An aggregation of SliceRecord-s from all the print objects for each // occupied layer. Slice record levels dont have to match exactly. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 87a322023..089fba656 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -430,10 +430,10 @@ bool BackgroundSlicingProcess::empty() const return m_print->empty(); } -std::string BackgroundSlicingProcess::validate() +std::string BackgroundSlicingProcess::validate(std::string* warning) { assert(m_print != nullptr); - return m_print->validate(); + return m_print->validate(warning); } // Apply config over the print. Returns false, if the new config values caused any of the already diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index b3f8a0a6b..d3819f15c 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -131,7 +131,7 @@ public: bool empty() const; // Validate the print. Returns an empty string if valid, returns an error message if invalid. // Call validate before calling start(). - std::string validate(); + std::string validate(std::string* warning = nullptr); // Set the export path of the G-code. // Once the path is set, the G-code diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 31dace42e..9ce278792 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -71,7 +71,9 @@ enum class NotificationType // Notification that custom supports/seams were deleted after mesh repair. CustomSupportsAndSeamRemovedAfterRepair, // Notification that auto adding of color changes is impossible - EmptyAutoColorChange + EmptyAutoColorChange, + // Notification emitted by Print::validate + PrintValidateWarning }; class NotificationManager diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 762acfdf1..93d0e0881 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1599,6 +1599,8 @@ struct Plater::priv void suppress_snapshots() { this->m_prevent_snapshots++; } void allow_snapshots() { this->m_prevent_snapshots--; } + void process_validation_warning(const std::string& warning) const; + bool background_processing_enabled() const { return this->get_config("background_processing") == "1"; } void update_print_volume_state(); void schedule_background_process(); @@ -2787,6 +2789,41 @@ void Plater::priv::update_print_volume_state() this->q->model().update_print_volume_state(print_volume); } + +void Plater::priv::process_validation_warning(const std::string& warning) const +{ + if (warning.empty()) + notification_manager->close_notification_of_type(NotificationType::PrintValidateWarning); + else { + std::string text = warning; + std::string hypertext = ""; + std::function action_fn = [](wxEvtHandler*){ return false; }; + + if (text == "_SUPPORTS_OFF") { + text = _u8L("An object has custom support enforcers which will not be used " + "because supports are disabled.")+"\n"; + hypertext = _u8L("Enable supports for enforcers only"); + action_fn = [](wxEvtHandler*) { + Tab* print_tab = wxGetApp().get_tab(Preset::TYPE_PRINT); + assert(print_tab); + DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + config.set_key_value("support_material", new ConfigOptionBool(true)); + config.set_key_value("support_material_auto", new ConfigOptionBool(false)); + print_tab->on_value_change("support_material", config.opt_bool("support_material")); + print_tab->on_value_change("support_material_auto", config.opt_bool("support_material_auto")); + return true; + }; + } + + notification_manager->push_notification( + NotificationType::PrintValidateWarning, + NotificationManager::NotificationLevel::ImportantNotification, + text, hypertext, action_fn + ); + } +} + + // Update background processing thread from the current config and Model. // Returns a bitmask of UpdateBackgroundProcessReturnState. unsigned int Plater::priv::update_background_process(bool force_validation, bool postpone_error_messages) @@ -2829,17 +2866,23 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // The delayed error message is no more valid. this->delayed_error_message.clear(); // The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors. - std::string err = this->background_process.validate(); + std::string warning; + std::string err = this->background_process.validate(&warning); if (err.empty()) { notification_manager->set_all_slicing_errors_gray(true); if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->background_processing_enabled()) return_state |= UPDATE_BACKGROUND_PROCESS_RESTART; + + // Pass a warning from validation and either show a notification, + // or hide the old one. + process_validation_warning(warning); } else { // The print is not valid. // Show error as notification. notification_manager->push_slicing_error_notification(err); return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; } + } else if (! this->delayed_error_message.empty()) { // Reusing the old state. return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;