From 44fa0ad857037f89650dd5c7679409b708bb1d11 Mon Sep 17 00:00:00 2001 From: supermerill Date: Thu, 16 Nov 2023 02:49:02 +0100 Subject: [PATCH] pause_print_gcode and color_change_gcode use default value if empty based on g-code flavor also: . moved the code inside gcodewriter to try to centralize at least a bit the code about firmware. . cleaned dead code in tab . removed the PausePrintCode in gcode writer . set firmware without the gcode support to "" so it isn't show by default. . add warning when creating gcode if we have a pause, no custom gcode, no default (possible when switching firmware) . little rewrite of how to pass the mutable part of print inside GCode . GCode no more a friend of Print Started by @your-friend-alice, thank you supermerill/SuperSlicer#3943 --- src/libslic3r/GCode.cpp | 134 ++++++++++++++++++-------------- src/libslic3r/GCode.hpp | 18 ++--- src/libslic3r/GCodeWriter.cpp | 30 ++++++- src/libslic3r/GCodeWriter.hpp | 4 +- src/libslic3r/Print.hpp | 24 +++++- src/libslic3r/PrintBase.hpp | 6 +- src/libslic3r/PrintConfig.cpp | 10 ++- src/slic3r/GUI/DoubleSlider.cpp | 14 ++-- src/slic3r/GUI/Tab.cpp | 6 -- 9 files changed, 158 insertions(+), 88 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index fc917dcea0b..da610ef95b0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -553,7 +553,7 @@ constexpr float SMALL_PERIMETER_SPEED_RATIO_OFFSET = (-10); // Collect pairs of object_layer + support_layer sorted by print_z. // object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON. -std::vector GCode::collect_layers_to_print(const PrintObject& object) +std::vector GCode::collect_layers_to_print(const PrintObject &object, Print::StatusMonitor &status_monitor) { std::vector layers_to_print; layers_to_print.reserve(object.layers().size() + object.support_layers().size()); @@ -676,7 +676,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec + _(L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. " "Try to repair the model or change its orientation on the bed.")); - const_cast(object.print())->active_step_add_warning( + status_monitor.active_step_add_warning( PrintStateBase::WarningLevel::CRITICAL, warning); } @@ -686,7 +686,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec // Prepare for non-sequential printing of multiple objects: Support resp. object layers with nearly identical print_z // will be printed for all objects at once. // Return a list of items. -std::vector>> GCode::collect_layers_to_print(const Print& print) +std::vector>> GCode::collect_layers_to_print(const Print &print, Print::StatusMonitor &status_monitor) { struct OrderingItem { coordf_t print_z; @@ -697,7 +697,7 @@ std::vector>> GCode::collec std::vector> per_object(print.objects().size(), std::vector()); std::vector ordering; for (size_t i = 0; i < print.objects().size(); ++i) { - per_object[i] = collect_layers_to_print(*print.objects()[i]); + per_object[i] = collect_layers_to_print(*print.objects()[i], status_monitor); OrderingItem ordering_item; ordering_item.object_idx = i; ordering.reserve(ordering.size() + per_object[i].size()); @@ -812,8 +812,8 @@ namespace DoExport { if (ret.size() < MAX_TAGS_COUNT) check(_(L("Extrusion type change G-code")), config.feature_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Tool change G-code")), config.toolchange_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Between objects G-code (for sequential printing)")), config.between_objects_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause Print G-code")), config.pause_print_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), GCodeWriter::get_default_color_change_gcode(config)); + if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause Print G-code")), GCodeWriter::get_default_pause_gcode(config)); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value); if (ret.size() < MAX_TAGS_COUNT) { for (const std::string& value : config.start_filament_gcode.values) { @@ -866,7 +866,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu if (print->is_step_done(psGCodeExport) && boost::filesystem::exists(boost::filesystem::path(path))) return; - print->set_started(psGCodeExport); + Print::StatusMonitor monitor{ *print }; + monitor.set_started(psGCodeExport); // check if any custom gcode contains keywords used by the gcode processor to // produce time estimation and gcode toolpaths @@ -876,7 +877,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu for (const auto& [source, keyword] : validation_res) { reports += source + ": \"" + keyword + "\"\n"; } - print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, + monitor.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, _(L("In the custom G-code were found reserved keywords:")) + "\n" + reports + _(L("This may cause problems in g-code visualization and printing time estimation."))); @@ -933,7 +934,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu // Post-process the G-code to update time stamps. m_processor.finalize(true); // DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics); - DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->config() ,print->m_print_statistics); + DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->config(), monitor.stats()); if (result != nullptr) { *result = std::move(m_processor.extract_result()); // set the filename to the correct value @@ -948,7 +949,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu } BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info(); - print->set_done(psGCodeExport); + monitor.set_done(psGCodeExport); //notify gui that the gcode is ready to be drawed print->set_status(100, "", PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); print->set_status(100, L("Gcode done"), PrintBase::SlicingStatus::FlagBits::GCODE_ENDED); @@ -1265,7 +1266,7 @@ std::vector sort_object_instances_by_model_order(const Pri // set standby temp for extruders // Parse the custom G-code, try to find T, and add it if not present -void GCode::_init_multiextruders(Print& print, GCodeOutputStream& file, GCodeWriter & writer, ToolOrdering &tool_ordering, const std::string &custom_gcode ) +void GCode::_init_multiextruders(const Print& print, GCodeOutputStream& file, GCodeWriter & writer, const ToolOrdering &tool_ordering, const std::string &custom_gcode ) { //set standby temp for reprap @@ -1283,10 +1284,13 @@ void GCode::_init_multiextruders(Print& print, GCodeOutputStream& file, GCodeWri } } -void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb) +void GCode::_do_export(Print& print_mod, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb) { PROFILE_FUNC(); + const Print &print = print_mod; + Print::StatusMonitor status_monitor{print_mod}; + //apply print config to m_config and m_writer, so we don't have to use print.config() instead // (and mostly to make m_writer.preamble() works) this->apply_print_config(print.config()); @@ -1315,8 +1319,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING m_fan_mover.release(); - print.m_print_statistics.color_extruderid_to_used_filament.clear(); - print.m_print_statistics.color_extruderid_to_used_weight.clear(); + status_monitor.stats().color_extruderid_to_used_filament.clear(); + status_monitor.stats().color_extruderid_to_used_weight.clear(); // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. @@ -1859,7 +1863,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Process all layers of a single object instance (sequential mode) with a parallel pipeline: // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser // and export G-code into file. - this->process_layers(print, print.m_print_statistics, tool_ordering, collect_layers_to_print(object), *print_object_instance_sequential_active - object.instances().data(), file); + this->process_layers(print, status_monitor, tool_ordering, collect_layers_to_print(object, status_monitor), + *print_object_instance_sequential_active - object.instances().data(), file); ++finished_objects; // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed. // Reset it when starting another object from 1st layer. @@ -1883,22 +1888,23 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato print_object_instance_sequential_active = print_object_instances_ordering.begin(); for (size_t i = 0; i < print.objects().size(); ++i, ++print_object_instance_sequential_active) { - std::vector object_layers = collect_layers_to_print(*print.objects()[i]); std::vector>> layers_to_print_range; - - int layer_num = 0; - for (const LayerToPrint& ltp : object_layers) { - layer_num++; - if (!first_layer && layer_num == 1) - continue; - - if (ltp.print_z() >= Rstart && ltp.print_z() < Rend) { - std::pair> merged; - merged.first = ltp.print_z(); - merged.second.emplace_back(ltp); - layers_to_print_range.emplace_back(merged); - if (first_layer) - break; + { + std::vector object_layers = collect_layers_to_print(*print.objects()[i], status_monitor); + int layer_num = 0; + for (LayerToPrint& ltp : object_layers) { + layer_num++; + if (!first_layer && layer_num == 1) + continue; + + if (ltp.print_z() >= Rstart && ltp.print_z() < Rend) { + std::pair> merged; + merged.first = ltp.print_z(); + merged.second.push_back(std::move(ltp)); + layers_to_print_range.emplace_back(merged); + if (first_layer) + break; + } } } @@ -1912,7 +1918,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->write_travel_to(gcode, polyline, "move to origin position for next object"); file.write(gcode); } - this->process_layers(print, print.m_print_statistics, tool_ordering, print_object_instances_ordering, layers_to_print_range, file); + this->process_layers(print, status_monitor, tool_ordering, print_object_instances_ordering, + layers_to_print_range, file); prev_object = print_object_instance_sequential_active; is_layers = true; } @@ -1929,7 +1936,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } else { // Sort layers by Z. // All extrusion moves with the same top layer height are extruded uninterrupted. - std::vector>> layers_to_print = collect_layers_to_print(print); + std::vector>> layers_to_print = collect_layers_to_print(print, status_monitor); // Prusa Multi-Material wipe tower. if (has_wipe_tower && !layers_to_print.empty()) { m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); @@ -1961,7 +1968,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // This is not Marlin, M1 command is probably not supported. // (See https://github.com/prusa3d/PrusaSlicer/issues/5441.) if (overlap) { - print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, + status_monitor.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, _(L("Your print is very close to the priming regions. " "Make sure there is no collision."))); } else { @@ -1975,7 +1982,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Process all layers of all objects (non-sequential mode) with a parallel pipeline: // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser // and export G-code into file. - this->process_layers(print, print.m_print_statistics, tool_ordering, print_object_instances_ordering, layers_to_print, file); + this->process_layers(print, status_monitor, tool_ordering, print_object_instances_ordering, layers_to_print, file); if (m_wipe_tower) // Purge the extruder, pull out the active filament. file.write(m_wipe_tower->finalize(*this)); @@ -2041,12 +2048,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_writer.extruders(), initial_extruder_id, // Modifies - print.m_print_statistics)); + status_monitor.stats())); file.write("\n"); - file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight); - file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost); - if (print.m_print_statistics.total_toolchanges > 0) - file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges); + file.write_format("; total filament used [g] = %.2lf\n", status_monitor.stats().total_weight); + file.write_format("; total filament cost = %.2lf\n", status_monitor.stats().total_cost); + if (status_monitor.stats().total_toolchanges > 0) + file.write_format("; total toolchanges = %i\n", status_monitor.stats().total_toolchanges); file.write_format("; total layers count = %i\n", m_layer_count); file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); @@ -2110,7 +2117,7 @@ class TBBLocalesSetter : public tbb::task_scheduler_observer // and export G-code into file. void GCode::process_layers( const Print &print, - PrintStatistics &print_stat, + Print::StatusMonitor &status_monitor, const ToolOrdering &tool_ordering, const std::vector &print_object_instances_ordering, const std::vector>> &layers_to_print, @@ -2119,7 +2126,7 @@ void GCode::process_layers( // The pipeline is variable: The vase mode filter is optional. size_t layer_to_print_idx = 0; const auto generator = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [this, &print, &print_stat, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> LayerResult { + [this, &print, &status_monitor, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> LayerResult { CNumericLocalesSetter locales_setter; if (layer_to_print_idx >= layers_to_print.size()) { if ((!m_pressure_equalizer && layer_to_print_idx == layers_to_print.size()) || (m_pressure_equalizer && layer_to_print_idx == (layers_to_print.size() + 1))) { @@ -2137,7 +2144,8 @@ void GCode::process_layers( if (m_wipe_tower && layer_tools.has_wipe_tower) m_wipe_tower->next_layer(); print.throw_if_canceled(); - return this->process_layer(print, print_stat, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1)); + return this->process_layer(print, status_monitor, layer.second, layer_tools, &layer == &layers_to_print.back(), + &print_object_instances_ordering, size_t(-1)); } }); const auto spiral_vase = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, @@ -2216,7 +2224,7 @@ void GCode::process_layers( // and export G-code into file. void GCode::process_layers( const Print &print, - PrintStatistics &print_stat, + Print::StatusMonitor &status_monitor, const ToolOrdering &tool_ordering, std::vector layers_to_print, const size_t single_object_idx, @@ -2225,7 +2233,7 @@ void GCode::process_layers( // The pipeline is variable: The vase mode filter is optional. size_t layer_to_print_idx = 0; const auto generator = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [this, &print, &print_stat, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> LayerResult { + [this, &print, &status_monitor, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> LayerResult { if (layer_to_print_idx >= layers_to_print.size()) { if ((!m_pressure_equalizer && layer_to_print_idx == layers_to_print.size()) || (m_pressure_equalizer && layer_to_print_idx == (layers_to_print.size() + 1))) { fc.stop(); @@ -2239,7 +2247,7 @@ void GCode::process_layers( } else { LayerToPrint &layer = layers_to_print[layer_to_print_idx ++]; print.throw_if_canceled(); - return this->process_layer(print, print_stat, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx); + return this->process_layer(print, status_monitor, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx); } }); const auto spiral_vase = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, @@ -2415,7 +2423,7 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc // Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters. // Do not process this piece of G-code by the time estimator, it already knows the values through another sources. -void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) +void GCode::print_machine_envelope(GCodeOutputStream &file, const Print &print) { // gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfKlipper, gcfSailfish, gcfSprinter, gcfMach3, gcfMachinekit, /// gcfSmoothie, gcfNoExtrusion, gcfLerdge, @@ -2493,7 +2501,7 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) // Only do that if the start G-code does not already contain any M-code controlling an extruder temperature. // M140 - Set Bed Temperature // M190 - Set Bed Temperature and Wait -void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait) +void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait) { // Initial bed temperature based on the first extruder. int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id); @@ -2516,7 +2524,7 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p // M104 - Set Extruder Temperature // M109 - Set Extruder Temperature and Wait // RepRapFirmware: G10 Sxx -void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait) +void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, const Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait) { // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; @@ -2634,7 +2642,7 @@ std::string emit_custom_gcode_per_print_z( // ID of the first extruder printing this layer. uint16_t first_extruder_id, const Print &print, - PrintStatistics &stats) + Print::StatusMonitor &status_emitter) { std::string gcode; bool single_extruder_printer = print.config().nozzle_diameter.size() == 1; @@ -2659,10 +2667,10 @@ std::string emit_custom_gcode_per_print_z( if (color_change) { //update stats : length double previously_extruded = 0; - for (const auto& tuple : stats.color_extruderid_to_used_filament) + for (const auto &tuple : status_emitter.stats().color_extruderid_to_used_filament) if (tuple.first == m600_extruder_before_layer) previously_extruded += tuple.second; - stats.color_extruderid_to_used_filament.emplace_back(m600_extruder_before_layer, gcodegen.writer().get_tool(m600_extruder_before_layer)->used_filament() - previously_extruded); + status_emitter.stats().color_extruderid_to_used_filament.emplace_back(m600_extruder_before_layer, gcodegen.writer().get_tool(m600_extruder_before_layer)->used_filament() - previously_extruded); } // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count @@ -2680,13 +2688,19 @@ std::string emit_custom_gcode_per_print_z( ) { //! FIXME_in_fw show message during print pause cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer)); - gcode += gcodegen.placeholder_parser_process("pause_print_gcode", print.config().pause_print_gcode, current_extruder_id, &cfg); + gcode += gcodegen.placeholder_parser_process("pause_print_gcode", GCodeWriter::get_default_pause_gcode(print.config()), current_extruder_id, &cfg); gcode += "\n"; gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n"; } else { + if (GCodeWriter::get_default_color_change_gcode(print.config()).empty()) { + status_emitter.active_step_add_warning( + PrintStateBase::WarningLevel::NON_CRITICAL, + _(L("Using a color change gcode, but there isn't one for this printer." + "\nThe printer won't stop for the filament change, unless you set it manually in the custom gcode section."))); + } cfg.set_key_value("color_change_extruder", new ConfigOptionInt(current_extruder_id)); // placeholder to avoid 'crashs' - gcode += gcodegen.placeholder_parser_process("color_change_gcode", print.config().color_change_gcode, current_extruder_id, &cfg); + gcode += gcodegen.placeholder_parser_process("color_change_gcode", GCodeWriter::get_default_color_change_gcode(print.config()), current_extruder_id, &cfg); gcode += "\n"; //FIXME Tell G-code writer that M600 filled the extruder, thus the G-code writer shall reset the extruder to unretracted state after // return from M600. Thus the G-code generated by the following line is ignored. @@ -2697,13 +2711,19 @@ std::string emit_custom_gcode_per_print_z( } else { if (gcode_type == CustomGCode::PausePrint) // Pause print - { + { + if (GCodeWriter::get_default_pause_gcode(print.config()).empty()) { + status_emitter.active_step_add_warning( + PrintStateBase::WarningLevel::NON_CRITICAL, + _(L("Using a pause gcode, but there isn't one for this printer." + "\nThe printer won't pause, unless you set it manually in the custom gcode section."))); + } // add tag for processor gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n"; //! FIXME_in_fw show message during print pause if (!pause_print_msg.empty()) gcode += "M117 " + pause_print_msg + "\n"; - gcode += gcodegen.placeholder_parser_process("pause_print_gcode", print.config().pause_print_gcode, current_extruder_id); + gcode += gcodegen.placeholder_parser_process("pause_print_gcode", GCodeWriter::get_default_pause_gcode(print.config()), current_extruder_id); } else { // add tag for processor gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Custom_Code) + "\n"; @@ -2805,7 +2825,7 @@ boost::regex regex_g92e0_gcode{ "^[ \\t]*[gG]92[ \\t]*[eE](0(\\.0*)?|\\.0+)[ \\t // and performing the extruder specific extrusions together. LayerResult GCode::process_layer( const Print &print, - PrintStatistics &print_stat, + Print::StatusMonitor &status_monitor, // Set of object & print layers of the same PrintObject and with the same print_z. const std::vector &layers, const LayerTools &layer_tools, @@ -2971,7 +2991,7 @@ LayerResult GCode::process_layer( if (single_object_instance_idx == size_t(-1)) { // Normal (non-sequential) print. - gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, layer_tools.custom_gcode, m_writer.tool()->id(), first_extruder_id, print, print_stat); + gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, layer_tools.custom_gcode, m_writer.tool()->id(), first_extruder_id, print, status_monitor); } // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index f3f9d1f5392..c2632d846ac 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -246,14 +246,14 @@ class GCode : ExtrusionVisitorConst { }; void _do_export(Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb); - void _init_multiextruders(Print& print, GCodeOutputStream& file, GCodeWriter& writer, ToolOrdering& tool_ordering, const std::string& custom_gcode); + void _init_multiextruders(const Print& print, GCodeOutputStream& file, GCodeWriter& writer, const ToolOrdering& tool_ordering, const std::string& custom_gcode); - static std::vector collect_layers_to_print(const PrintObject &object); - static std::vector>> collect_layers_to_print(const Print &print); + static std::vector collect_layers_to_print(const PrintObject &object, Print::StatusMonitor &status_monitor); + static std::vector>> collect_layers_to_print(const Print &print, Print::StatusMonitor &status_monitor); LayerResult process_layer( const Print &print, - PrintStatistics &print_stat, + Print::StatusMonitor &status_monitor, // Set of object & print layers of the same PrintObject and with the same print_z. const std::vector &layers, const LayerTools &layer_tools, @@ -269,7 +269,7 @@ class GCode : ExtrusionVisitorConst { // and export G-code into file. void process_layers( const Print &print, - PrintStatistics &print_stat, + Print::StatusMonitor &status_monitor, const ToolOrdering &tool_ordering, const std::vector &print_object_instances_ordering, const std::vector>> &layers_to_print, @@ -279,7 +279,7 @@ class GCode : ExtrusionVisitorConst { // and export G-code into file. void process_layers( const Print &print, - PrintStatistics &print_stat, + Print::StatusMonitor &status_monitor, const ToolOrdering &tool_ordering, std::vector layers_to_print, const size_t single_object_idx, @@ -506,9 +506,9 @@ class GCode : ExtrusionVisitorConst { std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); double_t _compute_speed_mm_per_sec(const ExtrusionPath& path, double speed = -1); std::string _after_extrude(const ExtrusionPath &path); - void print_machine_envelope(GCodeOutputStream &file, Print &print); - void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait); - void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait); + void print_machine_envelope(GCodeOutputStream &file, const Print &print); + void _print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait); + void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, const Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait); // On the first printing layer. This flag triggers first layer speeds. bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; } // To control print speed of 1st object layer over raft interface. diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index d9f261ffa31..c6f6a9a8d8b 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -29,8 +29,36 @@ #define E_NUM(val) PRECISION(val, this->config.gcode_precision_e.value) namespace Slic3r { +std::string GCodeWriter::get_default_pause_gcode(const GCodeConfig &config) +{ + if (config.pause_print_gcode.value.empty()) { + if (config.gcode_flavor.value == GCodeFlavor::gcfKlipper) { + return "PAUSE"; + } else if (config.gcode_flavor.value == GCodeFlavor::gcfRepRap || config.gcode_flavor.value == GCodeFlavor::gcfMarlinLegacy /*prusa only*/) { + return "M601"; + } else { + // no pause command for other firmware, for what i am aware. Please submit a pullrequest or issue if they change. + return ""; + } + } else { + return config.pause_print_gcode.value; + } +} -std::string GCodeWriter::PausePrintCode = "M601"; +std::string GCodeWriter::get_default_color_change_gcode(const GCodeConfig &config) +{ + if (config.color_change_gcode.value.empty()) { + if (config.gcode_flavor.value == GCodeFlavor::gcfRepRap || config.gcode_flavor.value == GCodeFlavor::gcfMarlinLegacy || + config.gcode_flavor.value == GCodeFlavor::gcfMarlinFirmware || config.gcode_flavor.value == GCodeFlavor::gcfSmoothie) { + return "M600"; + } else { + // no pause command for other firmware, for what i am aware. Please submit a pullrequest or issue if they change. + return ""; + } + } else { + return config.color_change_gcode.value; + } +} void GCodeWriter::apply_print_config(const PrintConfig &print_config) { diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index cb764840979..b0d3769843e 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -12,7 +12,6 @@ namespace Slic3r { class GCodeWriter { public: - static std::string PausePrintCode; GCodeConfig config; bool multiple_extruders; // override from region @@ -90,6 +89,9 @@ class GCodeWriter { std::string set_fan(uint8_t speed, uint16_t default_tool = 0); uint8_t get_fan() { return m_last_fan_speed; } + static std::string get_default_pause_gcode(const GCodeConfig &config); + static std::string get_default_color_change_gcode(const GCodeConfig &config); + private: // Extruders are sorted by their ID, so that binary search is possible. std::vector m_extruders; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 16094dfe17b..6eec0dc90d4 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -669,6 +669,28 @@ class Print : public PrintBaseWithState // Invalidates the step, and its depending steps in Print. //in public to invalidate gcode when the physical printer change. It's needed if we allow the gcode macro to read these values. bool invalidate_step(PrintStep step); + + // just a little wrapper to let the user know that this print can only be modified to emit warnings & update advancement status, change stats. + // TODO: have the status out of the printbase class and into another one, so we can have a const print & a mutable statusmonitor + class StatusMonitor + { + private: + Print& print; + + public: + StatusMonitor(Print &print_mutable) : print(print_mutable) {} + + // need this extra method because active_step_add_warning is protected and so need the friend status, and Gcode has it. + void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) + { + print.active_step_add_warning(warning_level, message, message_id); + } + PrintStatistics &stats() { return print.m_print_statistics; } + bool set_started(PrintStep step) { return print.set_started(step); } + PrintStateBase::TimeStamp set_done(PrintStep step) { return print.set_done(step); } + + }; + protected: private: @@ -708,8 +730,6 @@ class Print : public PrintBaseWithState // tiem of last change, to see if the gui need to be updated std::time_t m_timestamp_last_change; - // To allow GCode to set the Print's GCodeExport step status. - friend class GCode; // Allow PrintObject to access m_mutex and m_cancel_callback. friend class PrintObject; }; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 16a8c2f8471..e37ab0b3d72 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -505,6 +505,10 @@ class PrintBase : public ObjectBase // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. //public to ebablet ot call it from brim code. void throw_if_canceled() const { if (m_cancel_status.load(std::memory_order_acquire)) throw CanceledException(); } + + // Update "scale", "input_filename", "input_filename_base" placeholders from the current printable ModelObjects. + void update_object_placeholders(DynamicConfig &config, const std::string &default_ext) const; + protected: friend class PrintObjectBase; friend class BackgroundSlicingProcess; @@ -522,8 +526,6 @@ class PrintBase : public ObjectBase // To be called by this->output_filename() with the format string pulled from the configuration layer. std::string output_filename(const std::string &format, const std::string &default_ext, const std::string &filename_base, const DynamicConfig *config_override = nullptr) const; - // Update "scale", "input_filename", "input_filename_base" placeholders from the current printable ModelObjects. - void update_object_placeholders(DynamicConfig &config, const std::string &default_ext) const; Model m_model; DynamicPrintConfig m_full_print_config; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index bcf12182b34..36124b424d7 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5044,21 +5044,23 @@ void PrintConfigDef::init_fff_params() def = this->add("color_change_gcode", coString); def->label = L("Color change G-code"); - def->tooltip = L("This G-code will be used as a code for the color change"); + def->tooltip = L("This G-code will be used as a code for the color change" + " If empty, the default color change print command for the selected G-code flavor will be used (if any)."); def->multiline = true; def->full_width = true; def->height = 12; def->mode = comExpert | comPrusa; - def->set_default_value(new ConfigOptionString("M600")); + def->set_default_value(new ConfigOptionString("")); def = this->add("pause_print_gcode", coString); def->label = L("Pause Print G-code"); - def->tooltip = L("This G-code will be used as a code for the pause print"); + def->tooltip = L("This G-code will be used as a code for the pause print." + " If empty, the default pause print command for the selected G-code flavor will be used (if any)."); def->multiline = true; def->full_width = true; def->height = 12; def->mode = comExpert | comPrusa; - def->set_default_value(new ConfigOptionString("M601")); + def->set_default_value(new ConfigOptionString("")); def = this->add("template_custom_gcode", coString); def->label = L("Custom G-code"); diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 942433f759d..93d071a9370 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1,13 +1,14 @@ #include "libslic3r/libslic3r.h" #include "DoubleSlider.hpp" -#include "libslic3r/GCode.hpp" #include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "I18N.hpp" #include "ExtruderSequenceDialog.hpp" -#include "libslic3r/Print.hpp" #include "libslic3r/AppConfig.hpp" +#include "libslic3r/GCode.hpp" +#include "libslic3r/GCodeWriter.hpp" +#include "libslic3r/Print.hpp" #include "GUI_Utils.hpp" #include "MsgDialog.hpp" #include "Tab.hpp" @@ -51,10 +52,11 @@ wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); static std::string gcode(Type type) { - const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config(); + const Print& print = GUI::wxGetApp().plater()->fff_print(); + const PrintConfig &config = print.config(); switch (type) { - case ColorChange: return config.color_change_gcode; - case PausePrint: return config.pause_print_gcode; + case ColorChange: return Slic3r::GCodeWriter::get_default_color_change_gcode(config); + case PausePrint: return Slic3r::GCodeWriter::get_default_pause_gcode(config); case Template: return config.template_custom_gcode; default: return ""; } @@ -2014,7 +2016,7 @@ void Control::show_add_context_menu() { wxMenu menu; - if (m_mode == SingleExtruder) { + if (m_mode == SingleExtruder && !gcode(ColorChange).empty()) { append_menu_item(&menu, wxID_ANY, _L("Add color change") + " (" + gcode(ColorChange) + ")", "", [this](wxCommandEvent&) { add_code_as_tick(ColorChange); }, "colorchange_add_m", &menu); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 74ff54055f6..9da3eefced9 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -41,7 +41,6 @@ #include "PresetComboBoxes.hpp" #include -#include #include #include "GUI_App.hpp" @@ -3363,11 +3362,6 @@ void TabPrinter::toggle_options() field = get_field("silent_mode"); if (field) field->toggle(is_marlin_flavor); - if (m_config->option>("gcode_flavor")->value == gcfKlipper) - GCodeWriter::PausePrintCode = "PAUSE"; - else - GCodeWriter::PausePrintCode = "M601"; - if (m_last_gcode_flavor != uint8_t(m_config->option>("gcode_flavor")->value)) { m_last_gcode_flavor = uint8_t(m_config->option>("gcode_flavor")->value); m_rebuild_kinematics_page = true;