From 5b6aaf8c296052d0b3f679c4e8b46f7c46d5093f Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 29 May 2020 22:59:06 +0200 Subject: [PATCH] move warning about complete object from pop-up to red foreground message. --- src/PrusaSlicer.cpp | 6 +-- src/libslic3r/Print.cpp | 60 ++++++++++----------- src/libslic3r/Print.hpp | 2 +- src/libslic3r/PrintBase.hpp | 9 +++- src/libslic3r/SLAPrint.cpp | 22 ++++---- src/libslic3r/SLAPrint.hpp | 2 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 2 +- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 4 +- src/slic3r/GUI/GLCanvas3D.cpp | 23 ++++---- src/slic3r/GUI/GLCanvas3D.hpp | 10 +++- src/slic3r/GUI/Plater.cpp | 13 +++-- 11 files changed, 88 insertions(+), 65 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 4cbc1e24b..4c5f04360 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -425,9 +425,9 @@ int CLI::run(int argc, char **argv) fff_print.auto_assign_extruders(mo); } print->apply(model, m_print_config); - std::string err = print->validate(); - if (! err.empty()) { - boost::nowide::cerr << err << std::endl; + std::pair err = print->validate(); + if (! err.first == PrintError::None) { + boost::nowide::cerr << err.second << std::endl; return 1; } if (print->empty()) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4d386bd4c..91bf77bc3 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1273,19 +1273,19 @@ 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::pair Print::validate() const { if (m_objects.empty()) - return L("All objects are outside of the print volume."); + return { PrintError::WrongPosition, L("All objects are outside of the print volume.") }; if (extruders().empty()) - return L("The supplied settings will cause an empty print."); + return { PrintError::NoPrint, L("The supplied settings will cause an empty print.") }; if (m_config.complete_objects) { if (! sequential_print_horizontal_clearance_valid(*this)) - return L("Some objects are too close; your extruder will collide with them."); + return { PrintError::WrongPosition, L("Some objects are too close; your extruder will collide with them.") }; if (! sequential_print_vertical_clearance_valid(*this)) - return L("Some objects are too tall and cannot be printed without extruder collisions."); + return { PrintError::WrongPosition,L("Some objects are too tall and cannot be printed without extruder collisions.") }; } if (m_config.spiral_vase) { @@ -1294,14 +1294,14 @@ std::string Print::validate() const total_copies_count += object->instances().size(); // #4043 if (total_copies_count > 1 && ! m_config.complete_objects.value) - return L("The Spiral Vase option can only be used when printing a single object."); + return { PrintError::WrongSettings,L("The Spiral Vase option can only be used when printing a single object.") }; assert(m_objects.size() == 1 || config().complete_objects.value); size_t num_regions = 0; for (const std::vector> &volumes_per_region : m_objects.front()->region_volumes) if (! volumes_per_region.empty()) ++ num_regions; if (num_regions > 1) - return L("The Spiral Vase option can only be used when printing single material objects."); + return { PrintError::WrongSettings,L("The Spiral Vase option can only be used when printing single material objects.") }; } if (this->has_wipe_tower() && ! m_objects.empty()) { @@ -1314,21 +1314,21 @@ std::string Print::validate() const double filament_diam = m_config.filament_diameter.get_at(extruder_idx); if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam || std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) - return L("The wipe tower is only supported if all extruders have the same nozzle diameter " - "and use filaments of the same diameter."); + return { PrintError::WrongSettings,L("The wipe tower is only supported if all extruders have the same nozzle diameter " + "and use filaments of the same diameter.") }; } if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin && m_config.gcode_flavor != gcfKlipper) - return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors."); + return { PrintError::WrongSettings,L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.") }; if (! m_config.use_relative_e_distances) - return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); + return { PrintError::WrongSettings,L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; if (m_config.ooze_prevention) - return L("Ooze prevention is currently not supported with the wipe tower enabled."); + return { PrintError::WrongSettings,L("Ooze prevention is currently not supported with the wipe tower enabled.") }; if (m_config.use_volumetric_e) - return L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0)."); + return { PrintError::WrongSettings,L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0).") }; if (m_config.complete_objects && extruders().size() > 1) - return L("The Wipe Tower is currently not supported for multimaterial sequential prints."); + return { PrintError::WrongSettings,L("The Wipe Tower is currently not supported for multimaterial sequential prints.") }; if (m_objects.size() > 1) { bool has_custom_layering = false; @@ -1349,15 +1349,15 @@ std::string Print::validate() const const SlicingParameters &slicing_params = object->slicing_parameters(); if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON) - return L("The Wipe Tower is only supported for multiple objects if they have equal layer heights"); + return { PrintError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they have equal layer heights") }; if (slicing_params.raft_layers() != slicing_params0.raft_layers()) - return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"); + return { PrintError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers") }; if (object->config().support_material_contact_distance_type != m_objects.front()->config().support_material_contact_distance_type || object->config().support_material_contact_distance_top != m_objects.front()->config().support_material_contact_distance_top || object->config().support_material_contact_distance_bottom != m_objects.front()->config().support_material_contact_distance_bottom) - return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"); + return { PrintError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance") }; if (! equal_layering(slicing_params, slicing_params0)) - return L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); + return { PrintError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are sliced equally.") }; if (has_custom_layering) { PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]); if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2)) @@ -1399,7 +1399,7 @@ std::string Print::validate() const } while (ref_z == next_ref_z); } if (std::abs(this_height - ref_height) > EPSILON) - return L("The Wipe tower is only supported if all objects have the same variable layer height"); + return { PrintError::WrongSettings,L("The Wipe tower is only supported if all objects have the same variable layer height") }; i += 2; } } @@ -1448,20 +1448,20 @@ std::string Print::validate() const // The object has some form of support and either support_material_extruder or support_material_interface_extruder // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // are of the same diameter. - return L("Printing with multiple extruders of differing nozzle diameters. " + return { PrintError::WrongSettings,L("Printing with multiple extruders of differing nozzle diameters. " "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " - "all nozzles have to be of the same diameter."); + "all nozzles have to be of the same diameter.") }; } if (this->has_wipe_tower()) { if (object->config().support_material_contact_distance_type == zdNone) { // Soluble interface if (! object->config().support_material_synchronize_layers) - return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers."); + return { PrintError::WrongSettings,L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.") }; } else { // Non-soluble interface if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0) - return L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " - "(both support_material_extruder and support_material_interface_extruder need to be set to 0)."); + return { PrintError::WrongSettings,L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " + "(both support_material_extruder and support_material_interface_extruder need to be set to 0).") }; } } } @@ -1482,27 +1482,27 @@ std::string Print::validate() const first_layer_min_nozzle_diameter = min_nozzle_diameter; } if (first_layer_height > first_layer_min_nozzle_diameter) - return L("First layer height can't be greater than nozzle diameter"); + return { PrintError::WrongSettings,L("First layer height can't be greater than nozzle diameter") }; // validate layer_height double layer_height = object->config().layer_height.value; if (layer_height > min_nozzle_diameter) - return L("Layer height can't be greater than nozzle diameter"); + return { PrintError::WrongSettings,L("Layer height can't be greater than nozzle diameter") }; // Validate extrusion widths. std::string err_msg; if (! validate_extrusion_width(object->config(), "extrusion_width", layer_height, err_msg)) - return err_msg; + return { PrintError::WrongSettings,err_msg }; if ((object->config().support_material || object->config().raft_layers > 0) && ! validate_extrusion_width(object->config(), "support_material_extrusion_width", layer_height, err_msg)) - return err_msg; + return { PrintError::WrongSettings,err_msg }; for (const char *opt_key : { "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width" }) for (size_t i = 0; i < object->region_volumes.size(); ++ i) if (! object->region_volumes[i].empty() && ! validate_extrusion_width(this->get_region(i)->config(), opt_key, layer_height, err_msg)) - return err_msg; + return { PrintError::WrongSettings, err_msg }; } } - return std::string(); + return { PrintError::None, std::string() }; } #if 0 diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index dda947714..26617aba5 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -399,7 +399,7 @@ public: bool has_skirt() const; // Returns an empty string if valid, otherwise returns an error message. - std::string validate() const override; + std::pair validate() const override; double skirt_first_layer_height() const; Flow brim_flow(size_t extruder_id) const; Flow skirt_flow(size_t extruder_id) const; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 05d884cc8..79d6733b8 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -203,6 +203,13 @@ protected: ModelObject *m_model_object; }; +enum PrintError { + None, + WrongPosition, + NoPrint, + WrongSettings, +}; + /** * @brief Printing involves slicing and export of device dependent instructions. * @@ -229,7 +236,7 @@ public: virtual bool empty() 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::pair validate() const { return { PrintError::None, std::string() }; } enum ApplyStatus { // No change after the Print::apply() call. diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 52c6826c7..d97e6f503 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -602,7 +602,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::pairSLAPrint::validate() const { for(SLAPrintObject * po : m_objects) { @@ -612,8 +612,8 @@ std::string SLAPrint::validate() const if(supports_en && mo->sla_points_status == sla::PointsStatus::UserModified && mo->sla_support_points.empty()) - return L("Cannot proceed without support points! " - "Add support points or disable support generation."); + return { PrintError::WrongSettings, L("Cannot proceed without support points! " + "Add support points or disable support generation.") }; sla::SupportConfig cfg = make_support_cfg(po->config()); @@ -623,21 +623,21 @@ std::string SLAPrint::validate() const sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object; if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth()) - return L( + return { PrintError::WrongSettings, L( "Elevation is too low for object. Use the \"Pad around " - "object\" feature to print the object without elevation."); + "object\" feature to print the object without elevation.") }; if(supports_en && builtinpad.enabled && cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { - return L( + return { PrintError::WrongSettings, L( "The endings of the support pillars will be deployed on the " "gap between the object and the pad. 'Support base safety " "distance' has to be greater than the 'Pad object gap' " - "parameter to avoid this."); + "parameter to avoid this.") }; } std::string pval = padcfg.validate(); - if (!pval.empty()) return pval; + if (!pval.empty()) return { PrintError::WrongSettings, pval }; } double expt_max = m_printer_config.max_exposure_time.getFloat(); @@ -645,16 +645,16 @@ std::string SLAPrint::validate() const double expt_cur = m_material_config.exposure_time.getFloat(); if (expt_cur < expt_min || expt_cur > expt_max) - return L("Exposition time is out of printer profile bounds."); + return { PrintError::WrongSettings, L("Exposition time is out of printer profile bounds.") }; double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) - return L("Initial exposition time is out of printer profile bounds."); + return { PrintError::WrongSettings, L("Initial exposition time is out of printer profile bounds.") }; - return ""; + return { PrintError::None, "" }; } bool SLAPrint::invalidate_step(SLAPrintStep step) diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 70f773f6b..bccc04c91 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -432,7 +432,7 @@ public: const SLAPrintStatistics& print_statistics() const { return m_print_statistics; } - std::string validate() const override; + std::pair validate() 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 b3a50aa73..88245638e 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -373,7 +373,7 @@ bool BackgroundSlicingProcess::empty() const return m_print->empty(); } -std::string BackgroundSlicingProcess::validate() +std::pair BackgroundSlicingProcess::validate() { assert(m_print != nullptr); return m_print->validate(); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index d091ecb31..f9be42a72 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -92,9 +92,9 @@ public: void set_task(const PrintBase::TaskParams ¶ms); // After calling apply, the empty() call will report whether there is anything to slice. bool empty() const; - // Validate the print. Returns an empty string if valid, returns an error message if invalid. + // Validate the print. Returns a {PrintError::None,empty string} if valid, returns an error message if invalid. // Call validate before calling start(). - std::string validate(); + std::pair validate(); // Set the export path of the G-code. // Once the path is set, the G-code diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1dc2168f9..2e9599213 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -658,7 +658,7 @@ GLCanvas3D::WarningTexture::WarningTexture() { } -void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas) +void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas, std::string str_override) { auto it = std::find(m_warnings.begin(), m_warnings.end(), warning); @@ -682,19 +682,24 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool } // Look at the end of our vector and generate proper texture. - std::string text; + std::string text = str_override; bool red_colored = false; - switch (m_warnings.back()) { - case ObjectOutside : text = L("An object outside the print area was detected"); break; - case ToolpathOutside : text = L("A toolpath outside the print area was detected"); break; - case SlaSupportsOutside : text = L("SLA supports outside the print area were detected"); break; - case SomethingNotShown : text = L("Some objects are not visible"); break; + if (text.empty()) { + switch (m_warnings.back()) { + case ObjectOutside: text = L("An object outside the print area was detected"); break; + case ToolpathOutside: text = L("A toolpath outside the print area was detected"); break; + case SlaSupportsOutside: text = L("SLA supports outside the print area were detected"); break; + case SomethingNotShown: text = L("Some objects are not visible"); break; case ObjectClashed: { text = L("An object outside the print area was detected\n" - "Resolve the current problem to continue slicing"); + "Resolve the current problem to continue slicing"); red_colored = true; break; } + default: text = L("An error occured"); + } + } else { + red_colored = true; } generate(text, canvas, true, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) @@ -6664,7 +6669,7 @@ void GLCanvas3D::_show_warning_texture_if_needed(WarningTexture::Warning warning { _set_current(); _set_warning_texture(warning, _is_any_volume_outside()); - } +} std::vector GLCanvas3D::_parse_colors(const std::vector& colors) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index c8d8326e7..11a6e9200 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -314,12 +314,13 @@ private: ToolpathOutside, SlaSupportsOutside, SomethingNotShown, + PrintWarning, ObjectClashed }; // Sets a warning of the given type to be active/inactive. If several warnings are active simultaneously, // only the last one is shown (decided by the order in the enum above). - void activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas); + void activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas, std::string str_override = ""); void render(const GLCanvas3D& canvas) const; // function used to get an information for rescaling of the warning @@ -699,6 +700,13 @@ public: bool are_labels_shown() const { return m_labels.is_shown(); } void show_labels(bool show) { m_labels.show(show); } + void show_print_warning(std::string str) { + if (str.empty()) + m_warning_texture.activate(WarningTexture::Warning::PrintWarning, false, *this); + else + m_warning_texture.activate(WarningTexture::Warning::PrintWarning, true, *this, str); + } + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e00911046..0d45928c8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3165,8 +3165,9 @@ 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(); - if (err.empty()) { + std::pair err = this->background_process.validate(); + this->get_current_canvas3D()->show_print_warning(""); + if (err.first == PrintError::None) { if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->background_processing_enabled()) return_state |= UPDATE_BACKGROUND_PROCESS_RESTART; } else { @@ -3176,12 +3177,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool while (p->GetParent()) p = p->GetParent(); auto *top_level_wnd = dynamic_cast(p); - if (! postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) { + if ( (err.first == PrintError::WrongPosition || err.first == PrintError::NoPrint) && top_level_wnd && top_level_wnd->IsActive()) { + this->get_current_canvas3D()->show_print_warning(err.second); + } else if (!postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) { // The error returned from the Print needs to be translated into the local language. - GUI::show_error(this->q, err); + GUI::show_error(this->q, err.second); } else { // Show the error message once the main window gets activated. - this->delayed_error_message = err; + this->delayed_error_message = err.second; } return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; }