mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge remote-tracking branch 'remotes/origin/amf_activate_existing_presets'
This commit is contained in:
		
						commit
						210eeff160
					
				
					 18 changed files with 487 additions and 129 deletions
				
			
		|  | @ -22,6 +22,7 @@ xs/src/slic3r/GUI/UpdateDialogs.cpp | |||
| xs/src/slic3r/GUI/WipeTowerDialog.cpp | ||||
| xs/src/slic3r/Utils/OctoPrint.cpp | ||||
| xs/src/slic3r/Utils/PresetUpdater.cpp | ||||
| xs/src/libslic3r/Print.cpp | ||||
| xs/src/libslic3r/PrintConfig.cpp | ||||
| xs/src/libslic3r/GCode/PreviewData.cpp | ||||
| lib/Slic3r/GUI.pm | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| // Escape \n, \r and backslash
 | ||||
| std::string escape_string_cstyle(const std::string &str) | ||||
| { | ||||
|     // Allocate a buffer twice the input string length,
 | ||||
|  | @ -28,9 +29,15 @@ std::string escape_string_cstyle(const std::string &str) | |||
|     char *outptr = out.data(); | ||||
|     for (size_t i = 0; i < str.size(); ++ i) { | ||||
|         char c = str[i]; | ||||
|         if (c == '\n' || c == '\r') { | ||||
|         if (c == '\r') { | ||||
|             (*outptr ++) = '\\'; | ||||
|             (*outptr ++) = 'r'; | ||||
|         } else if (c == '\n') { | ||||
|             (*outptr ++) = '\\'; | ||||
|             (*outptr ++) = 'n'; | ||||
|         } else if (c == '\\') { | ||||
|             (*outptr ++) = '\\'; | ||||
|             (*outptr ++) = '\\'; | ||||
|         } else | ||||
|             (*outptr ++) = c; | ||||
|     } | ||||
|  | @ -69,7 +76,10 @@ std::string escape_strings_cstyle(const std::vector<std::string> &strs) | |||
|                 if (c == '\\' || c == '"') { | ||||
|                     (*outptr ++) = '\\'; | ||||
|                     (*outptr ++) = c; | ||||
|                 } else if (c == '\n' || c == '\r') { | ||||
|                 } else if (c == '\r') { | ||||
|                     (*outptr ++) = '\\'; | ||||
|                     (*outptr ++) = 'r'; | ||||
|                 } else if (c == '\n') { | ||||
|                     (*outptr ++) = '\\'; | ||||
|                     (*outptr ++) = 'n'; | ||||
|                 } else | ||||
|  | @ -84,6 +94,7 @@ std::string escape_strings_cstyle(const std::vector<std::string> &strs) | |||
|     return std::string(out.data(), outptr - out.data()); | ||||
| } | ||||
| 
 | ||||
| // Unescape \n, \r and backslash
 | ||||
| bool unescape_string_cstyle(const std::string &str, std::string &str_out) | ||||
| { | ||||
|     std::vector<char> out(str.size(), 0); | ||||
|  | @ -94,8 +105,12 @@ bool unescape_string_cstyle(const std::string &str, std::string &str_out) | |||
|             if (++ i == str.size()) | ||||
|                 return false; | ||||
|             c = str[i]; | ||||
|             if (c == 'n') | ||||
|             if (c == 'r') | ||||
|                 (*outptr ++) = '\r'; | ||||
|             else if (c == 'n') | ||||
|                 (*outptr ++) = '\n'; | ||||
|             else | ||||
|                 (*outptr ++) = c; | ||||
|         } else | ||||
|             (*outptr ++) = c; | ||||
|     } | ||||
|  | @ -134,7 +149,9 @@ bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &o | |||
|                     if (++ i == str.size()) | ||||
|                         return false; | ||||
|                     c = str[i]; | ||||
|                     if (c == 'n') | ||||
|                     if (c == 'r') | ||||
|                         c = '\r'; | ||||
|                     else if (c == 'n') | ||||
|                         c = '\n'; | ||||
|                 } | ||||
|                 buf.push_back(c); | ||||
|  | @ -188,7 +205,10 @@ void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys | |||
|             throw UnknownOptionException(opt_key); | ||||
|         } | ||||
| 		const ConfigOption *other_opt = other.option(opt_key); | ||||
|         if (other_opt != nullptr) | ||||
| 		if (other_opt == nullptr) { | ||||
|             // The key was not found in the source config, therefore it will not be initialized!
 | ||||
| //			printf("Not found, therefore not initialized: %s\n", opt_key.c_str());
 | ||||
| 		} else | ||||
|             my_opt->set(other_opt); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -291,6 +291,8 @@ public: | |||
|     ConfigOptionFloats() : ConfigOptionVector<double>() {} | ||||
|     explicit ConfigOptionFloats(size_t n, double value) : ConfigOptionVector<double>(n, value) {} | ||||
|     explicit ConfigOptionFloats(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {} | ||||
|     explicit ConfigOptionFloats(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {} | ||||
|     explicit ConfigOptionFloats(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {} | ||||
| 
 | ||||
|     static ConfigOptionType static_type() { return coFloats; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|  |  | |||
|  | @ -1411,15 +1411,22 @@ void GCode::apply_print_config(const PrintConfig &print_config) | |||
| 
 | ||||
| void GCode::append_full_config(const Print& print, std::string& str) | ||||
| { | ||||
|     const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config }; | ||||
|     const StaticPrintConfig *configs[] = { static_cast<const GCodeConfig*>(&print.config), &print.default_object_config, &print.default_region_config }; | ||||
|     for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) { | ||||
|         const StaticPrintConfig *cfg = configs[i]; | ||||
|         for (const std::string &key : cfg->keys()) | ||||
|         { | ||||
|             if (key != "compatible_printers") | ||||
|                 str += "; " + key + " = " + cfg->serialize(key) + "\n"; | ||||
|         } | ||||
|     } | ||||
|     const DynamicConfig &full_config = print.placeholder_parser.config(); | ||||
| 	for (const char *key : { | ||||
| 		"print_settings_id", "filament_settings_id", "printer_settings_id", | ||||
| 		"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", | ||||
| 		"compatible_printers_condition_cummulative", "inherits_cummulative" }) { | ||||
| 		const ConfigOption *opt = full_config.option(key); | ||||
| 		if (opt != nullptr) | ||||
| 			str += std::string("; ") + key + " = " + opt->serialize() + "\n"; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids) | ||||
|  |  | |||
|  | @ -2,7 +2,12 @@ | |||
| #include "PreviewData.hpp" | ||||
| #include <float.h> | ||||
| #include <wx/intl.h>  | ||||
| #include "slic3r/GUI/GUI.hpp" | ||||
| #include <I18N.hpp> | ||||
| 
 | ||||
| #include <boost/format.hpp> | ||||
| 
 | ||||
| //! macro used to mark string used at localization, 
 | ||||
| #define L(s) (s) | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -405,7 +410,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: | |||
|             items.reserve(last_valid - first_valid + 1); | ||||
|             for (unsigned int i = (unsigned int)first_valid; i <= (unsigned int)last_valid; ++i) | ||||
|             { | ||||
|                 items.emplace_back(_CHB(extrusion.role_names[i].c_str()).data(), extrusion.role_colors[i]); | ||||
|                 items.emplace_back(Slic3r::I18N::translate(extrusion.role_names[i]), extrusion.role_colors[i]); | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|  | @ -436,13 +441,9 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: | |||
|             items.reserve(tools_colors_count); | ||||
|             for (unsigned int i = 0; i < tools_colors_count; ++i) | ||||
|             { | ||||
| 				char buf[MIN_BUF_LENGTH_FOR_L]; | ||||
|                 sprintf(buf, _CHB(L("Extruder %d")), i + 1); | ||||
| 
 | ||||
|                 GCodePreviewData::Color color; | ||||
|                 ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float)); | ||||
| 
 | ||||
|                 items.emplace_back(buf, color); | ||||
|                 items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color); | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|  |  | |||
							
								
								
									
										18
									
								
								xs/src/libslic3r/I18N.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								xs/src/libslic3r/I18N.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| #ifndef slic3r_I18N_hpp_ | ||||
| #define slic3r_I18N_hpp_ | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| namespace I18N { | ||||
| 	typedef std::string (*translate_fn_type)(const char*); | ||||
| 	extern translate_fn_type translate_fn; | ||||
| 	inline void set_translate_callback(translate_fn_type fn) { translate_fn = fn; } | ||||
| 	inline std::string translate(const std::string &s) { return (translate_fn == nullptr) ? s : (*translate_fn)(s.c_str()); } | ||||
| 	inline std::string translate(const char *ptr) { return (translate_fn == nullptr) ? std::string(ptr) : (*translate_fn)(ptr); } | ||||
| } // namespace I18N
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| #endif /* slic3r_I18N_hpp_ */ | ||||
|  | @ -4,6 +4,7 @@ | |||
| #include "Extruder.hpp" | ||||
| #include "Flow.hpp" | ||||
| #include "Geometry.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "SupportMaterial.hpp" | ||||
| #include "GCode/WipeTowerPrusaMM.hpp" | ||||
| #include <algorithm> | ||||
|  | @ -11,6 +12,10 @@ | |||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| 
 | ||||
| //! macro used to mark string used at localization, 
 | ||||
| //! return same string
 | ||||
| #define L(s) Slic3r::I18N::translate(s) | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| template class PrintState<PrintStep, psCount>; | ||||
|  | @ -523,7 +528,7 @@ std::string Print::validate() const | |||
|     print_volume.min.z = -1e10; | ||||
|     for (PrintObject *po : this->objects) { | ||||
|         if (!print_volume.contains(po->model_object()->tight_bounding_box(false))) | ||||
|             return "Some objects are outside of the print volume."; | ||||
|             return L("Some objects are outside of the print volume."); | ||||
|     } | ||||
| 
 | ||||
|     if (this->config.complete_objects) { | ||||
|  | @ -550,7 +555,7 @@ std::string Print::validate() const | |||
|                     Polygon p = convex_hull; | ||||
|                     p.translate(copy); | ||||
|                     if (! intersection(convex_hulls_other, p).empty()) | ||||
|                         return "Some objects are too close; your extruder will collide with them."; | ||||
|                         return L("Some objects are too close; your extruder will collide with them."); | ||||
|                     polygons_append(convex_hulls_other, p); | ||||
|                 } | ||||
|             } | ||||
|  | @ -565,7 +570,7 @@ std::string Print::validate() const | |||
|             // it will be printed as last one so its height doesn't matter.
 | ||||
|             object_height.pop_back(); | ||||
|             if (! object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value)) | ||||
|                 return "Some objects are too tall and cannot be printed without extruder collisions."; | ||||
|                 return L("Some objects are too tall and cannot be printed without extruder collisions."); | ||||
|         } | ||||
|     } // end if (this->config.complete_objects)
 | ||||
| 
 | ||||
|  | @ -575,27 +580,22 @@ std::string Print::validate() const | |||
|             total_copies_count += object->copies().size(); | ||||
|         // #4043
 | ||||
|         if (total_copies_count > 1 && ! this->config.complete_objects.value) | ||||
|             return "The Spiral Vase option can only be used when printing a single object."; | ||||
|             return L("The Spiral Vase option can only be used when printing a single object."); | ||||
|         if (this->regions.size() > 1) | ||||
|             return "The Spiral Vase option can only be used when printing single material objects."; | ||||
|             return L("The Spiral Vase option can only be used when printing single material objects."); | ||||
|     } | ||||
| 
 | ||||
|     if (this->config.single_extruder_multi_material) { | ||||
|         for (size_t i=1; i<this->config.nozzle_diameter.values.size(); ++i) | ||||
|             if (this->config.nozzle_diameter.values[i] != this->config.nozzle_diameter.values[i-1]) | ||||
|                 return "All extruders must have the same diameter for single extruder multimaterial printer."; | ||||
|                 return L("All extruders must have the same diameter for single extruder multimaterial printer."); | ||||
|     } | ||||
| 
 | ||||
|     if (this->has_wipe_tower() && ! this->objects.empty()) { | ||||
|         #if 0 | ||||
|         for (auto dmr : this->config.nozzle_diameter.values) | ||||
|             if (std::abs(dmr - 0.4) > EPSILON) | ||||
|                 return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter."; | ||||
|         #endif | ||||
|         if (this->config.gcode_flavor != gcfRepRap && this->config.gcode_flavor != gcfMarlin) | ||||
|             return "The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors."; | ||||
|             return L("The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors."); | ||||
|         if (! this->config.use_relative_e_distances) | ||||
|             return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."; | ||||
|             return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); | ||||
|         SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters(); | ||||
| 
 | ||||
|         const PrintObject* tallest_object = this->objects.front(); // let's find the tallest object
 | ||||
|  | @ -607,13 +607,13 @@ std::string Print::validate() 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 "The Wipe Tower is only supported for multiple objects if they have equal layer heigths"; | ||||
|                 return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths"); | ||||
|             if (slicing_params.raft_layers() != slicing_params0.raft_layers()) | ||||
|                 return "The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"; | ||||
|                 return 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 != this->objects.front()->config.support_material_contact_distance) | ||||
|                 return "The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"; | ||||
|                 return 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 "The Wipe Tower is only supported for multiple objects if they are sliced equally."; | ||||
|                 return L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); | ||||
|             bool was_layer_height_profile_valid = object->layer_height_profile_valid; | ||||
|             object->update_layer_height_profile(); | ||||
|             object->layer_height_profile_valid = was_layer_height_profile_valid; | ||||
|  | @ -637,13 +637,8 @@ std::string Print::validate() const | |||
|                     failed = true; | ||||
| 
 | ||||
|                 if (failed) | ||||
|                     return "The Wipe tower is only supported if all objects have the same layer height profile"; | ||||
|                     return L("The Wipe tower is only supported if all objects have the same layer height profile"); | ||||
|             } | ||||
| 
 | ||||
|             /*for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
 | ||||
|                 if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON && | ||||
|                     std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON) | ||||
|                     return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";*/ | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | @ -651,7 +646,7 @@ std::string Print::validate() const | |||
|         // find the smallest nozzle diameter
 | ||||
|         std::vector<unsigned int> extruders = this->extruders(); | ||||
|         if (extruders.empty()) | ||||
|             return "The supplied settings will cause an empty print."; | ||||
|             return L("The supplied settings will cause an empty print."); | ||||
|          | ||||
|         std::vector<double> nozzle_diameters; | ||||
|         for (unsigned int extruder_id : extruders) | ||||
|  | @ -661,7 +656,7 @@ std::string Print::validate() const | |||
|         unsigned int total_extruders_count = this->config.nozzle_diameter.size(); | ||||
|         for (const auto& extruder_idx : extruders) | ||||
|             if ( extruder_idx >= total_extruders_count ) | ||||
|                 return "One or more object were assigned an extruder that the printer does not have."; | ||||
|                 return L("One or more object were assigned an extruder that the printer does not have."); | ||||
| 
 | ||||
|         for (PrintObject *object : this->objects) { | ||||
|             if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) && | ||||
|  | @ -670,13 +665,13 @@ std::string Print::validate() const | |||
|                 // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
 | ||||
|                 // are of the same diameter.
 | ||||
|                 if (nozzle_diameters.size() > 1) | ||||
|                     return "Printing with multiple extruders of differing nozzle diameters. " | ||||
|                     return 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."); | ||||
|             } | ||||
|              | ||||
|             // validate first_layer_height
 | ||||
|             double first_layer_height = object->config.get_abs_value("first_layer_height"); | ||||
|             double first_layer_height = object->config.get_abs_value(L("first_layer_height")); | ||||
|             double first_layer_min_nozzle_diameter; | ||||
|             if (object->config.raft_layers > 0) { | ||||
|                 // if we have raft layers, only support material extruder is used on first layer
 | ||||
|  | @ -691,11 +686,11 @@ std::string Print::validate() const | |||
|                 first_layer_min_nozzle_diameter = min_nozzle_diameter; | ||||
|             } | ||||
|             if (first_layer_height > first_layer_min_nozzle_diameter) | ||||
|                 return "First layer height can't be greater than nozzle diameter"; | ||||
|                 return L("First layer height can't be greater than nozzle diameter"); | ||||
|              | ||||
|             // validate layer_height
 | ||||
|             if (object->config.layer_height.value > min_nozzle_diameter) | ||||
|                 return "Layer height can't be greater than nozzle diameter"; | ||||
|                 return L("Layer height can't be greater than nozzle diameter"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1212,7 +1207,7 @@ std::string Print::output_filename() | |||
|     try { | ||||
|         return this->placeholder_parser.process(this->config.output_filename_format.value, 0); | ||||
|     } catch (std::runtime_error &err) { | ||||
|         throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what()); | ||||
|         throw std::runtime_error(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,10 @@ | |||
| #include "PrintConfig.hpp" | ||||
| #include "I18N.hpp" | ||||
| 
 | ||||
| #include <set> | ||||
| #include <boost/algorithm/string/replace.hpp> | ||||
| #include <boost/algorithm/string/case_conv.hpp> | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/thread.hpp> | ||||
| 
 | ||||
|  | @ -11,7 +14,7 @@ namespace Slic3r { | |||
| 
 | ||||
| //! macro used to mark string used at localization, 
 | ||||
| //! return same string
 | ||||
| #define L(s) s | ||||
| #define L(s) Slic3r::I18N::translate(s) | ||||
| 
 | ||||
| PrintConfigDef::PrintConfigDef() | ||||
| { | ||||
|  | @ -151,6 +154,11 @@ PrintConfigDef::PrintConfigDef() | |||
|                    "with the active printer profile."); | ||||
|     def->default_value = new ConfigOptionString(); | ||||
| 
 | ||||
|     // The following value is to be stored into the project file (AMF, 3MF, Config ...)
 | ||||
|     // and it contains a sum of "compatible_printers_condition" values over the print and filament profiles.
 | ||||
|     def = this->add("compatible_printers_condition_cummulative", coStrings); | ||||
|     def->default_value = new ConfigOptionStrings(); | ||||
| 
 | ||||
|     def = this->add("complete_objects", coBool); | ||||
|     def->label = L("Complete individual objects"); | ||||
|     def->tooltip = L("When printing multiple objects or copies, this feature will complete " | ||||
|  | @ -821,7 +829,12 @@ PrintConfigDef::PrintConfigDef() | |||
|     def->tooltip = L("Name of the profile, from which this profile inherits."); | ||||
|     def->full_width = true; | ||||
|     def->height = 50; | ||||
|     def->default_value = new ConfigOptionString(""); | ||||
|     def->default_value = new ConfigOptionString(); | ||||
| 
 | ||||
|     // The following value is to be stored into the project file (AMF, 3MF, Config ...)
 | ||||
|     // and it contains a sum of "inherits" values over the print and filament profiles.
 | ||||
|     def = this->add("inherits_cummulative", coStrings); | ||||
|     def->default_value = new ConfigOptionStrings(); | ||||
| 
 | ||||
|     def = this->add("interface_shells", coBool); | ||||
|     def->label = L("Interface shells"); | ||||
|  | @ -853,6 +866,85 @@ PrintConfigDef::PrintConfigDef() | |||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloat(0.3); | ||||
| 
 | ||||
| 	{ | ||||
| 		struct AxisDefault { | ||||
| 			std::string         name; | ||||
| 			std::vector<double> max_feedrate; | ||||
| 			std::vector<double> max_acceleration; | ||||
| 			std::vector<double> max_jerk; | ||||
| 		}; | ||||
| 		std::vector<AxisDefault> axes { | ||||
| 			// name, max_feedrate,  max_acceleration, max_jerk
 | ||||
| 			{ "x", { 200., 200. }, { 1000., 1000. }, { 10., 10. } }, | ||||
| 			{ "y", { 200., 200. }, { 1000., 1000. }, { 10., 10. } }, | ||||
| 			{ "z", { 12., 12. }, { 200., 200. }, { 0.4, 0.4 } }, | ||||
| 			{ "e", { 120., 120. }, { 5000., 5000. }, { 2.5, 2.5 } } | ||||
| 		}; | ||||
| 		for (const AxisDefault &axis : axes) { | ||||
| 			std::string axis_upper = boost::to_upper_copy<std::string>(axis.name); | ||||
| 			// Add the machine feedrate limits for XYZE axes. (M203)
 | ||||
| 			def = this->add("machine_max_feedrate_" + axis.name, coFloats); | ||||
| 			def->label = (boost::format(L("Maximum feedrate %1%")) % axis_upper).str(); | ||||
| 			def->category = L("Machine limits"); | ||||
| 			def->tooltip  = (boost::format(L("Maximum feedrate of the %1% axis")) % axis_upper).str(); | ||||
| 			def->sidetext = L("mm/s"); | ||||
| 			def->min = 0; | ||||
| 			def->default_value = new ConfigOptionFloats(axis.max_feedrate); | ||||
| 			// Add the machine acceleration limits for XYZE axes (M201)
 | ||||
| 			def = this->add("machine_max_acceleration_" + axis.name, coFloats); | ||||
| 			def->label = (boost::format(L("Maximum acceleration %1%")) % axis_upper).str(); | ||||
| 			def->category = L("Machine limits"); | ||||
| 			def->tooltip  = (boost::format(L("Maximum acceleration of the %1% axis")) % axis_upper).str(); | ||||
| 			def->sidetext = L("mm/s²"); | ||||
| 			def->min = 0; | ||||
| 			def->default_value = new ConfigOptionFloats(axis.max_acceleration); | ||||
| 			// Add the machine jerk limits for XYZE axes (M205)
 | ||||
| 			def = this->add("machine_max_jerk_" + axis.name, coFloats); | ||||
| 			def->label = (boost::format(L("Maximum jerk %1%")) % axis_upper).str(); | ||||
| 			def->category = L("Machine limits"); | ||||
| 			def->tooltip  = (boost::format(L("Maximum jerk of the %1% axis")) % axis_upper).str(); | ||||
| 			def->sidetext = L("mm/s"); | ||||
| 			def->min = 0; | ||||
| 			def->default_value = new ConfigOptionFloats(axis.max_jerk); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     // M205 S... [mm/sec]
 | ||||
|     def = this->add("machine_min_extruding_rate", coFloats); | ||||
|     def->label = L("Minimum feedrate when extruding"); | ||||
|     def->category = L("Machine limits"); | ||||
|     def->tooltip = L("Minimum feedrate when extruding") + " (M205 S)"; | ||||
|     def->sidetext = L("mm/s"); | ||||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloats(0., 0.); | ||||
| 
 | ||||
|     // M205 T... [mm/sec]
 | ||||
|     def = this->add("machine_min_travel_rate", coFloats); | ||||
|     def->label = L("Minimum travel feedrate"); | ||||
|     def->category = L("Machine limits"); | ||||
|     def->tooltip = L("Minimum travel feedrate") + " (M205 T)"; | ||||
|     def->sidetext = L("mm/s"); | ||||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloats(0., 0.); | ||||
| 
 | ||||
|     // M204 S... [mm/sec^2]
 | ||||
|     def = this->add("machine_max_acceleration_extruding", coFloats); | ||||
|     def->label = L("Maximum acceleration when extruding"); | ||||
|     def->category = L("Machine limits"); | ||||
|     def->tooltip = L("Maximum acceleration when extruding") + " (M204 S)"; | ||||
|     def->sidetext = L("mm/s²"); | ||||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloats(1250., 1250.); | ||||
| 
 | ||||
|     // M204 T... [mm/sec^2]
 | ||||
|     def = this->add("machine_max_acceleration_retracting", coFloats); | ||||
|     def->label = L("Maximum acceleration when retracting"); | ||||
|     def->category = L("Machine limits"); | ||||
|     def->tooltip = L("Maximum acceleration when retracting") + " (M204 T)"; | ||||
|     def->sidetext = L("mm/s²"); | ||||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloats(1250., 1250.); | ||||
| 
 | ||||
|     def = this->add("max_fan_speed", coInts); | ||||
|     def->label = L("Max"); | ||||
|     def->tooltip = L("This setting represents the maximum speed of your fan."); | ||||
|  | @ -2198,6 +2290,7 @@ std::string FullPrintConfig::validate() | |||
| // Declare the static caches for each StaticPrintConfig derived class.
 | ||||
| StaticPrintConfig::StaticCache<class Slic3r::PrintObjectConfig> PrintObjectConfig::s_cache_PrintObjectConfig; | ||||
| StaticPrintConfig::StaticCache<class Slic3r::PrintRegionConfig> PrintRegionConfig::s_cache_PrintRegionConfig; | ||||
| StaticPrintConfig::StaticCache<class Slic3r::MachineEnvelopeConfig> MachineEnvelopeConfig::s_cache_MachineEnvelopeConfig; | ||||
| StaticPrintConfig::StaticCache<class Slic3r::GCodeConfig>       GCodeConfig::s_cache_GCodeConfig; | ||||
| StaticPrintConfig::StaticCache<class Slic3r::PrintConfig>       PrintConfig::s_cache_PrintConfig; | ||||
| StaticPrintConfig::StaticCache<class Slic3r::HostConfig>        HostConfig::s_cache_HostConfig; | ||||
|  |  | |||
|  | @ -455,6 +455,56 @@ protected: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| class MachineEnvelopeConfig : public StaticPrintConfig | ||||
| { | ||||
|     STATIC_PRINT_CONFIG_CACHE(MachineEnvelopeConfig) | ||||
| public: | ||||
|     // M201 X... Y... Z... E... [mm/sec^2]
 | ||||
|     ConfigOptionFloats              machine_max_acceleration_x; | ||||
|     ConfigOptionFloats              machine_max_acceleration_y; | ||||
|     ConfigOptionFloats              machine_max_acceleration_z; | ||||
|     ConfigOptionFloats              machine_max_acceleration_e; | ||||
|     // M203 X... Y... Z... E... [mm/sec]
 | ||||
|     ConfigOptionFloats              machine_max_feedrate_x; | ||||
|     ConfigOptionFloats              machine_max_feedrate_y; | ||||
|     ConfigOptionFloats              machine_max_feedrate_z; | ||||
|     ConfigOptionFloats              machine_max_feedrate_e; | ||||
|     // M204 S... [mm/sec^2]
 | ||||
|     ConfigOptionFloats              machine_max_acceleration_extruding; | ||||
|     // M204 T... [mm/sec^2]
 | ||||
|     ConfigOptionFloats              machine_max_acceleration_retracting; | ||||
|     // M205 X... Y... Z... E... [mm/sec]
 | ||||
|     ConfigOptionFloats              machine_max_jerk_x; | ||||
|     ConfigOptionFloats              machine_max_jerk_y; | ||||
|     ConfigOptionFloats              machine_max_jerk_z; | ||||
|     ConfigOptionFloats              machine_max_jerk_e; | ||||
|     // M205 T... [mm/sec]
 | ||||
|     ConfigOptionFloats              machine_min_travel_rate; | ||||
|     // M205 S... [mm/sec]
 | ||||
|     ConfigOptionFloats              machine_min_extruding_rate; | ||||
| 
 | ||||
| protected: | ||||
|     void initialize(StaticCacheBase &cache, const char *base_ptr) | ||||
|     { | ||||
|         OPT_PTR(machine_max_acceleration_x); | ||||
|         OPT_PTR(machine_max_acceleration_y); | ||||
|         OPT_PTR(machine_max_acceleration_z); | ||||
|         OPT_PTR(machine_max_acceleration_e); | ||||
|         OPT_PTR(machine_max_feedrate_x); | ||||
|         OPT_PTR(machine_max_feedrate_y); | ||||
|         OPT_PTR(machine_max_feedrate_z); | ||||
|         OPT_PTR(machine_max_feedrate_e); | ||||
|         OPT_PTR(machine_max_acceleration_extruding); | ||||
|         OPT_PTR(machine_max_acceleration_retracting); | ||||
|         OPT_PTR(machine_max_jerk_x); | ||||
|         OPT_PTR(machine_max_jerk_y); | ||||
|         OPT_PTR(machine_max_jerk_z); | ||||
|         OPT_PTR(machine_max_jerk_e); | ||||
|         OPT_PTR(machine_min_travel_rate); | ||||
|         OPT_PTR(machine_min_extruding_rate); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // This object is mapped to Perl as Slic3r::Config::GCode.
 | ||||
| class GCodeConfig : public StaticPrintConfig | ||||
| { | ||||
|  | @ -566,7 +616,7 @@ protected: | |||
| }; | ||||
| 
 | ||||
| // This object is mapped to Perl as Slic3r::Config::Print.
 | ||||
| class PrintConfig : public GCodeConfig | ||||
| class PrintConfig : public MachineEnvelopeConfig, public GCodeConfig | ||||
| { | ||||
|     STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig) | ||||
|     PrintConfig() : GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); } | ||||
|  | @ -642,6 +692,7 @@ protected: | |||
|     PrintConfig(int) : GCodeConfig(1) {} | ||||
|     void initialize(StaticCacheBase &cache, const char *base_ptr) | ||||
|     { | ||||
|         this->MachineEnvelopeConfig::initialize(cache, base_ptr); | ||||
|         this->GCodeConfig::initialize(cache, base_ptr); | ||||
|         OPT_PTR(avoid_crossing_perimeters); | ||||
|         OPT_PTR(bed_shape); | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include "Utils.hpp" | ||||
| #include "I18N.hpp" | ||||
| 
 | ||||
| #include <locale> | ||||
| #include <ctime> | ||||
|  | @ -123,6 +124,9 @@ const std::string& localization_dir() | |||
| 	return g_local_dir; | ||||
| } | ||||
| 
 | ||||
| // Translate function callback, to call wxWidgets translate function to convert non-localized UTF8 string to a localized one.
 | ||||
| Slic3r::I18N::translate_fn_type Slic3r::I18N::translate_fn = nullptr; | ||||
| 
 | ||||
| static std::string g_data_dir; | ||||
| 
 | ||||
| void set_data_dir(const std::string &dir) | ||||
|  |  | |||
|  | @ -56,9 +56,9 @@ | |||
| 
 | ||||
| #include "../Utils/PresetUpdater.hpp" | ||||
| #include "../Config/Snapshot.hpp" | ||||
| #include "libslic3r/I18N.hpp" | ||||
| #include "3DScene.hpp" | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| #if __APPLE__ | ||||
|  | @ -150,9 +150,13 @@ void update_label_colours_from_appconfig() | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); } | ||||
| 
 | ||||
| void set_wxapp(wxApp *app) | ||||
| { | ||||
|     g_wxApp = app; | ||||
|     // Let the libslic3r know the callback, which will translate messages on demand.
 | ||||
| 	Slic3r::I18N::set_translate_callback(libslic3r_translate_callback); | ||||
|     init_label_colours(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,11 +33,14 @@ class PresetUpdater; | |||
| class DynamicPrintConfig; | ||||
| class TabIface; | ||||
| 
 | ||||
| #define _(s)    Slic3r::translate((s)) | ||||
| inline wxString translate(const char *s)    	 { return wxGetTranslation(wxString(s, wxConvUTF8)); } | ||||
| inline wxString translate(const wchar_t *s) 	 { return wxGetTranslation(s); } | ||||
| inline wxString translate(const std::string &s)  { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)); } | ||||
| inline wxString translate(const std::wstring &s) { return wxGetTranslation(s.c_str()); } | ||||
| #define _(s)    Slic3r::GUI::I18N::translate((s)) | ||||
| 
 | ||||
| namespace GUI { namespace I18N { | ||||
| 	inline wxString translate(const char *s)    	 { return wxGetTranslation(wxString(s, wxConvUTF8)); } | ||||
| 	inline wxString translate(const wchar_t *s) 	 { return wxGetTranslation(s); } | ||||
| 	inline wxString translate(const std::string &s)  { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)); } | ||||
| 	inline wxString translate(const std::wstring &s) { return wxGetTranslation(s.c_str()); } | ||||
| } } | ||||
| 
 | ||||
| // !!! If you needed to translate some wxString,
 | ||||
| // !!! please use _(L(string))
 | ||||
|  |  | |||
|  | @ -234,12 +234,12 @@ std::string Preset::label() const | |||
| 
 | ||||
| bool Preset::is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const | ||||
| { | ||||
|     auto *condition               = dynamic_cast<const ConfigOptionString*>(this->config.option("compatible_printers_condition")); | ||||
|     auto &condition               = this->compatible_printers_condition(); | ||||
|     auto *compatible_printers     = dynamic_cast<const ConfigOptionStrings*>(this->config.option("compatible_printers")); | ||||
|     bool  has_compatible_printers = compatible_printers != nullptr && ! compatible_printers->values.empty(); | ||||
|     if (! has_compatible_printers && condition != nullptr && ! condition->value.empty()) { | ||||
|     if (! has_compatible_printers && ! condition.empty()) { | ||||
|         try { | ||||
|             return PlaceholderParser::evaluate_boolean_expression(condition->value, active_printer.config, extra_config); | ||||
|             return PlaceholderParser::evaluate_boolean_expression(condition, active_printer.config, extra_config); | ||||
|         } catch (const std::runtime_error &err) { | ||||
|             //FIXME in case of an error, return "compatible with everything".
 | ||||
|             printf("Preset::is_compatible_with_printer - parsing error of compatible_printers_condition %s:\n%s\n", active_printer.name.c_str(), err.what()); | ||||
|  | @ -424,7 +424,87 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string | |||
| { | ||||
|     DynamicPrintConfig cfg(this->default_preset().config); | ||||
|     cfg.apply_only(config, cfg.keys(), true); | ||||
|     return this->load_preset(path, name, std::move(cfg)); | ||||
|     return this->load_preset(path, name, std::move(cfg), select); | ||||
| } | ||||
| 
 | ||||
| static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const DynamicPrintConfig &cfg2) | ||||
| { | ||||
|     t_config_option_keys diff = cfg1.diff(cfg2); | ||||
|     // Following keys are used by the UI, not by the slicing core, therefore they are not important
 | ||||
|     // when comparing profiles for equality. Ignore them.
 | ||||
|     for (const char *key : { "compatible_printers", "compatible_printers_condition", "inherits",  | ||||
|                              "print_settings_id", "filament_settings_id", "printer_settings_id", | ||||
|                              "printer_model", "printer_variant", "default_print_profile", "default_filament_profile" }) | ||||
|         diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end()); | ||||
|     // Preset with the same name as stored inside the config exists.
 | ||||
|     return diff.empty(); | ||||
| } | ||||
| 
 | ||||
| // Load a preset from an already parsed config file, insert it into the sorted sequence of presets
 | ||||
| // and select it, losing previous modifications.
 | ||||
| // In case 
 | ||||
| Preset& PresetCollection::load_external_preset( | ||||
|     // Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
 | ||||
|     const std::string           &path, | ||||
|     // Name of the profile, derived from the source file name.
 | ||||
|     const std::string           &name, | ||||
|     // Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
 | ||||
|     const std::string           &original_name, | ||||
|     // Config to initialize the preset from.
 | ||||
|     const DynamicPrintConfig    &config, | ||||
|     // Select the preset after loading?
 | ||||
|     bool                         select) | ||||
| { | ||||
|     // Load the preset over a default preset, so that the missing fields are filled in from the default preset.
 | ||||
|     DynamicPrintConfig cfg(this->default_preset().config); | ||||
|     cfg.apply_only(config, cfg.keys(), true); | ||||
|     // Is there a preset already loaded with the name stored inside the config?
 | ||||
|     std::deque<Preset>::iterator it = this->find_preset_internal(original_name); | ||||
|     if (it != m_presets.end() && it->name == original_name && profile_print_params_same(it->config, cfg)) { | ||||
|         // The preset exists and it matches the values stored inside config.
 | ||||
|         if (select) | ||||
|             this->select_preset(it - m_presets.begin()); | ||||
|         return *it; | ||||
|     } | ||||
|     // Update the "inherits" field.
 | ||||
|     std::string &inherits = Preset::inherits(cfg); | ||||
|     if (it != m_presets.end() && inherits.empty()) { | ||||
|         // There is a profile with the same name already loaded. Should we update the "inherits" field?
 | ||||
|         if (it->vendor == nullptr) | ||||
|             inherits = it->inherits(); | ||||
|         else | ||||
|             inherits = it->name; | ||||
|     } | ||||
|     // The external preset does not match an internal preset, load the external preset.
 | ||||
|     std::string new_name; | ||||
|     for (size_t idx = 0;; ++ idx) { | ||||
|         std::string suffix; | ||||
|         if (original_name.empty()) { | ||||
|             if (idx > 0) | ||||
|                 suffix = " (" + std::to_string(idx) + ")"; | ||||
|         } else { | ||||
|             if (idx == 0) | ||||
|                 suffix = " (" + original_name + ")";             | ||||
|             else | ||||
|                 suffix = " (" + original_name + "-" + std::to_string(idx) + ")"; | ||||
|         } | ||||
|         new_name = name + suffix; | ||||
|         it = this->find_preset_internal(new_name); | ||||
|         if (it == m_presets.end() || it->name != new_name) | ||||
|             // Unique profile name. Insert a new profile.
 | ||||
|             break; | ||||
|         if (profile_print_params_same(it->config, cfg)) { | ||||
|             // The preset exists and it matches the values stored inside config.
 | ||||
|             if (select) | ||||
|                 this->select_preset(it - m_presets.begin()); | ||||
|             return *it; | ||||
|         } | ||||
|         // Form another profile name.
 | ||||
|     } | ||||
|     // Insert a new profile.
 | ||||
|     Preset &preset = this->load_preset(path, new_name, std::move(cfg), select); | ||||
|     preset.is_external = true; | ||||
|     return preset; | ||||
| } | ||||
| 
 | ||||
| Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select) | ||||
|  | @ -460,7 +540,7 @@ void PresetCollection::save_current_preset(const std::string &new_name) | |||
|     } else { | ||||
|         // Creating a new preset.
 | ||||
| 		Preset       &preset   = *m_presets.insert(it, m_edited_preset); | ||||
|         std::string  &inherits = preset.config.opt_string("inherits", true); | ||||
|         std::string  &inherits = preset.inherits(); | ||||
|         std::string   old_name = preset.name; | ||||
|         preset.name = new_name; | ||||
| 		preset.file = this->path_from_name(new_name); | ||||
|  | @ -475,7 +555,6 @@ void PresetCollection::save_current_preset(const std::string &new_name) | |||
|             // Inherited from a user preset. Just maintain the "inherited" flag, 
 | ||||
|             // meaning it will inherit from either the system preset, or the inherited user preset.
 | ||||
|         } | ||||
|         preset.inherits = inherits; | ||||
|         preset.is_default  = false; | ||||
|         preset.is_system   = false; | ||||
|         preset.is_external = false; | ||||
|  | @ -513,20 +592,20 @@ bool PresetCollection::load_bitmap_default(const std::string &file_name) | |||
| 
 | ||||
| const Preset* PresetCollection::get_selected_preset_parent() const | ||||
| { | ||||
|     auto *inherits = dynamic_cast<const ConfigOptionString*>(this->get_edited_preset().config.option("inherits")); | ||||
|     if (inherits == nullptr || inherits->value.empty()) | ||||
| 		return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; // nullptr; 
 | ||||
|     const Preset* preset = this->find_preset(inherits->value, false); | ||||
|     const std::string &inherits = this->get_edited_preset().inherits(); | ||||
|     if (inherits.empty()) | ||||
| 		return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;  | ||||
|     const Preset* preset = this->find_preset(inherits, false); | ||||
|     return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset; | ||||
| } | ||||
| 
 | ||||
| const Preset* PresetCollection::get_preset_parent(const Preset& child) const | ||||
| { | ||||
|     auto *inherits = dynamic_cast<const ConfigOptionString*>(child.config.option("inherits")); | ||||
|     if (inherits == nullptr || inherits->value.empty()) | ||||
|     const std::string &inherits = child.inherits(); | ||||
|     if (inherits.empty()) | ||||
| // 		return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; 
 | ||||
| 		return nullptr;  | ||||
|     const Preset* preset = this->find_preset(inherits->value, false); | ||||
|     const Preset* preset = this->find_preset(inherits, false); | ||||
|     return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset; | ||||
| } | ||||
| 
 | ||||
|  | @ -763,7 +842,7 @@ std::vector<std::string> PresetCollection::dirty_options(const Preset *edited, c | |||
|         // The "compatible_printers" option key is handled differently from the others:
 | ||||
|         // It is not mandatory. If the key is missing, it means it is compatible with any printer.
 | ||||
|         // If the key exists and it is empty, it means it is compatible with no printer.
 | ||||
|         std::initializer_list<const char*> optional_keys { "compatible_printers", "compatible_printers_condition" }; | ||||
|         std::initializer_list<const char*> optional_keys { "compatible_printers" }; | ||||
|         for (auto &opt_key : optional_keys) { | ||||
|             if (reference->config.has(opt_key) != edited->config.has(opt_key)) | ||||
|                 changed.emplace_back(opt_key); | ||||
|  | @ -772,17 +851,6 @@ std::vector<std::string> PresetCollection::dirty_options(const Preset *edited, c | |||
|     return changed; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string>    PresetCollection::system_equal_options() const | ||||
| { | ||||
| 	const Preset *edited = &this->get_edited_preset(); | ||||
| 	const Preset *reference = this->get_selected_preset_parent(); | ||||
| 	std::vector<std::string> equal; | ||||
| 	if (edited != nullptr && reference != nullptr) { | ||||
| 		equal = reference->config.equal(edited->config); | ||||
| 	} | ||||
| 	return equal; | ||||
| } | ||||
| 
 | ||||
| // Select a new preset. This resets all the edits done to the currently selected preset.
 | ||||
| // If the preset with index idx does not exist, a first visible preset is selected.
 | ||||
| Preset& PresetCollection::select_preset(size_t idx) | ||||
|  |  | |||
|  | @ -113,9 +113,6 @@ public: | |||
|     // or a Configuration file bundling the Print + Filament + Printer presets (in that case is_external and possibly is_system will be true),
 | ||||
|     // or it could be a G-code (again, is_external will be true).
 | ||||
|     std::string         file; | ||||
|     // A user profile may inherit its settings either from a system profile, or from a user profile.
 | ||||
|     // A system profile shall never derive from any other profile, as the system profile hierarchy is being flattened during loading.
 | ||||
|     std::string         inherits; | ||||
|     // If this is a system profile, then there should be a vendor data available to display at the UI.
 | ||||
|     const VendorProfile *vendor      = nullptr; | ||||
| 
 | ||||
|  | @ -142,6 +139,16 @@ public: | |||
|     bool                is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const; | ||||
|     bool                is_compatible_with_printer(const Preset &active_printer) const; | ||||
| 
 | ||||
|     // Returns the name of the preset, from which this preset inherits.
 | ||||
|     static std::string& inherits(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("inherits", true)->value; } | ||||
|     std::string&        inherits() { return Preset::inherits(this->config); } | ||||
|     const std::string&  inherits() const { return Preset::inherits(const_cast<Preset*>(this)->config); } | ||||
| 
 | ||||
|     // Returns the "compatible_printers_condition".
 | ||||
|     static std::string& compatible_printers_condition(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("compatible_printers_condition", true)->value; } | ||||
|     std::string&        compatible_printers_condition() { return Preset::compatible_printers_condition(this->config); } | ||||
|     const std::string&  compatible_printers_condition() const { return Preset::compatible_printers_condition(const_cast<Preset*>(this)->config); } | ||||
| 
 | ||||
|     // Mark this preset as compatible if it is compatible with active_printer.
 | ||||
|     bool                update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config); | ||||
| 
 | ||||
|  | @ -200,6 +207,18 @@ public: | |||
|     Preset&         load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true); | ||||
|     Preset&         load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true); | ||||
| 
 | ||||
|     Preset&         load_external_preset( | ||||
|         // Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
 | ||||
|         const std::string           &path, | ||||
|         // Name of the profile, derived from the source file name.
 | ||||
|         const std::string           &name, | ||||
|         // Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
 | ||||
|         const std::string           &original_name, | ||||
|         // Config to initialize the preset from.
 | ||||
|         const DynamicPrintConfig    &config, | ||||
|         // Select the preset after loading?
 | ||||
|         bool                         select = true); | ||||
| 
 | ||||
|     // Save the preset under a new name. If the name is different from the old one,
 | ||||
|     // a new preset is stored into the list of presets.
 | ||||
|     // All presets are marked as not modified and the new preset is activated.
 | ||||
|  | @ -312,8 +331,6 @@ public: | |||
|     // Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ.
 | ||||
|     std::vector<std::string>    current_different_from_parent_options(const bool is_printer_type = false) const | ||||
|         { return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), is_printer_type); } | ||||
|     // Compare the content of get_selected_preset() with get_selected_preset_parent() configs, return the list of keys where they equal.
 | ||||
| 	std::vector<std::string>    system_equal_options() const; | ||||
| 
 | ||||
|     // Update the choice UI from the list of presets.
 | ||||
|     // If show_incompatible, all presets are shown, otherwise only the compatible presets are shown.
 | ||||
|  | @ -349,9 +366,10 @@ private: | |||
|     PresetCollection(const PresetCollection &other); | ||||
|     PresetCollection& operator=(const PresetCollection &other); | ||||
| 
 | ||||
|     // Find a preset in the sorted list of presets.
 | ||||
|     // Find a preset position in the sorted list of presets.
 | ||||
|     // The "-- default -- " preset is always the first, so it needs
 | ||||
|     // to be handled differently.
 | ||||
|     // If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
 | ||||
|     std::deque<Preset>::iterator find_preset_internal(const std::string &name) | ||||
|     { | ||||
|         Preset key(m_type, name); | ||||
|  |  | |||
|  | @ -52,26 +52,37 @@ PresetBundle::PresetBundle() : | |||
|     if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) | ||||
|         wxImage::AddHandler(new wxPNGHandler); | ||||
| 
 | ||||
|     // The following keys are handled by the UI, they do not have a counterpart in any StaticPrintConfig derived classes,
 | ||||
|     // therefore they need to be handled differently. As they have no counterpart in StaticPrintConfig, they are not being
 | ||||
|     // initialized based on PrintConfigDef(), but to empty values (zeros, empty vectors, empty strings).
 | ||||
|     //
 | ||||
|     // "compatible_printers", "compatible_printers_condition", "inherits",
 | ||||
|     // "print_settings_id", "filament_settings_id", "printer_settings_id",
 | ||||
|     // "printer_vendor", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile"
 | ||||
| 
 | ||||
|     // Create the ID config keys, as they are not part of the Static print config classes.
 | ||||
|     this->prints.default_preset().config.opt_string("print_settings_id", true); | ||||
|     this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values.assign(1, std::string()); | ||||
|     this->printers.default_preset().config.opt_string("printer_settings_id", true); | ||||
|     // "compatible printers" are not mandatory yet. 
 | ||||
|     //FIXME Rename "compatible_printers" and "compatible_printers_condition", as they are defined in both print and filament profiles,
 | ||||
|     // therefore they are clashing when generating a a config file, G-code or AMF/3MF.
 | ||||
| //    this->filaments.default_preset().config.optptr("compatible_printers", true);
 | ||||
| //    this->filaments.default_preset().config.optptr("compatible_printers_condition", true);
 | ||||
| //    this->prints.default_preset().config.optptr("compatible_printers", true);
 | ||||
| //    this->prints.default_preset().config.optptr("compatible_printers_condition", true);
 | ||||
|     // Create the "printer_vendor", "printer_model" and "printer_variant" keys.
 | ||||
|     this->prints.default_preset().config.optptr("print_settings_id", true); | ||||
|     this->prints.default_preset().compatible_printers_condition(); | ||||
|     this->prints.default_preset().inherits(); | ||||
| 
 | ||||
|     this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values = { "" }; | ||||
|     this->filaments.default_preset().compatible_printers_condition(); | ||||
|     this->filaments.default_preset().inherits(); | ||||
| 
 | ||||
|     this->printers.default_preset().config.optptr("printer_settings_id", true); | ||||
|     this->printers.default_preset().config.optptr("printer_vendor", true); | ||||
|     this->printers.default_preset().config.optptr("printer_model", true); | ||||
|     this->printers.default_preset().config.optptr("printer_variant", true); | ||||
|     // Load the default preset bitmaps.
 | ||||
|     this->printers.default_preset().config.optptr("default_print_profile", true); | ||||
|     this->printers.default_preset().config.option<ConfigOptionStrings>("default_filament_profile", true)->values = { "" }; | ||||
| 	this->printers.default_preset().inherits(); | ||||
| 
 | ||||
| 	// Load the default preset bitmaps.
 | ||||
|     this->prints   .load_bitmap_default("cog.png"); | ||||
|     this->filaments.load_bitmap_default("spool.png"); | ||||
|     this->printers .load_bitmap_default("printer_empty.png"); | ||||
|     this->load_compatible_bitmaps(); | ||||
| 
 | ||||
|     // Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above.
 | ||||
|     this->prints   .select_preset(0); | ||||
|     this->filaments.select_preset(0); | ||||
|  | @ -372,9 +383,16 @@ DynamicPrintConfig PresetBundle::full_config() const | |||
| 
 | ||||
|     auto   *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(out.option("nozzle_diameter")); | ||||
|     size_t  num_extruders   = nozzle_diameter->values.size(); | ||||
|     // Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
 | ||||
|     std::vector<std::string> compatible_printers_condition; | ||||
|     std::vector<std::string> inherits; | ||||
|     compatible_printers_condition.emplace_back(this->prints.get_edited_preset().compatible_printers_condition()); | ||||
|     inherits                     .emplace_back(this->prints.get_edited_preset().inherits()); | ||||
| 
 | ||||
|     if (num_extruders <= 1) { | ||||
|         out.apply(this->filaments.get_edited_preset().config); | ||||
|         compatible_printers_condition.emplace_back(this->filaments.get_edited_preset().compatible_printers_condition()); | ||||
|         inherits                     .emplace_back(this->filaments.get_edited_preset().inherits()); | ||||
|     } else { | ||||
|         // Retrieve filament presets and build a single config object for them.
 | ||||
|         // First collect the filament configurations based on the user selection of this->filament_presets.
 | ||||
|  | @ -384,11 +402,15 @@ DynamicPrintConfig PresetBundle::full_config() const | |||
|             filament_configs.emplace_back(&this->filaments.find_preset(filament_preset_name, true)->config); | ||||
| 		while (filament_configs.size() < num_extruders) | ||||
|             filament_configs.emplace_back(&this->filaments.first_visible().config); | ||||
|         for (const DynamicPrintConfig *cfg : filament_configs) { | ||||
|             compatible_printers_condition.emplace_back(Preset::compatible_printers_condition(*const_cast<DynamicPrintConfig*>(cfg))); | ||||
|             inherits                     .emplace_back(Preset::inherits(*const_cast<DynamicPrintConfig*>(cfg))); | ||||
|         } | ||||
|         // Option values to set a ConfigOptionVector from.
 | ||||
|         std::vector<const ConfigOption*> filament_opts(num_extruders, nullptr); | ||||
|         // loop through options and apply them to the resulting config.
 | ||||
|         for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) { | ||||
| 			if (key == "compatible_printers" || key == "compatible_printers_condition") | ||||
| 			if (key == "compatible_printers") | ||||
| 				continue; | ||||
|             // Get a destination option.
 | ||||
|             ConfigOption *opt_dst = out.option(key, false); | ||||
|  | @ -406,9 +428,13 @@ DynamicPrintConfig PresetBundle::full_config() const | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //FIXME These two value types clash between the print and filament profiles. They should be renamed.
 | ||||
| 	// Don't store the "compatible_printers_condition" for the printer profile, there is none.
 | ||||
|     inherits.emplace_back(this->printers.get_edited_preset().inherits()); | ||||
| 
 | ||||
|     // These two value types clash between the print and filament profiles. They should be renamed.
 | ||||
|     out.erase("compatible_printers"); | ||||
|     out.erase("compatible_printers_condition"); | ||||
|     out.erase("inherits"); | ||||
|      | ||||
|     static const char *keys[] = { "perimeter", "infill", "solid_infill", "support_material", "support_material_interface" }; | ||||
|     for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++ i) { | ||||
|  | @ -418,6 +444,25 @@ DynamicPrintConfig PresetBundle::full_config() const | |||
|         opt->value = boost::algorithm::clamp<int>(opt->value, 0, int(num_extruders)); | ||||
|     } | ||||
| 
 | ||||
|     out.option<ConfigOptionString >("print_settings_id",    true)->value  = this->prints.get_selected_preset().name; | ||||
|     out.option<ConfigOptionStrings>("filament_settings_id", true)->values = this->filament_presets; | ||||
|     out.option<ConfigOptionString >("printer_settings_id",  true)->value  = this->printers.get_selected_preset().name; | ||||
| 
 | ||||
|     // Serialize the collected "compatible_printers_condition" and "inherits" fields.
 | ||||
|     // There will be 1 + num_exturders fields for "inherits" and 2 + num_extruders for "compatible_printers_condition" stored.
 | ||||
|     // The vector will not be stored if all fields are empty strings.
 | ||||
|     auto add_if_some_non_empty = [&out](std::vector<std::string> &&values, const std::string &key) { | ||||
|         bool nonempty = false; | ||||
|         for (const std::string &v : values) | ||||
|             if (! v.empty()) { | ||||
|                 nonempty = true; | ||||
|                 break; | ||||
|             } | ||||
|         if (nonempty) | ||||
|             out.set_key_value(key, new ConfigOptionStrings(std::move(values))); | ||||
|     }; | ||||
|     add_if_some_non_empty(std::move(compatible_printers_condition), "compatible_printers_condition_cummulative"); | ||||
|     add_if_some_non_empty(std::move(inherits),                      "inherits_cummulative"); | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
|  | @ -496,6 +541,18 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     size_t num_extruders = std::min(config.option<ConfigOptionFloats>("nozzle_diameter"  )->values.size(),  | ||||
|                                     config.option<ConfigOptionFloats>("filament_diameter")->values.size()); | ||||
|     // Make a copy of the "compatible_printers_condition_cummulative" and "inherits_cummulative" vectors, which 
 | ||||
|     // accumulate values over all presets (print, filaments, printers).
 | ||||
|     // These values will be distributed into their particular presets when loading.
 | ||||
|     std::vector<std::string> compatible_printers_condition_values   = std::move(config.option<ConfigOptionStrings>("compatible_printers_condition_cummulative", true)->values); | ||||
|     std::vector<std::string> inherits_values                        = std::move(config.option<ConfigOptionStrings>("inherits_cummulative", true)->values); | ||||
|     std::string &compatible_printers_condition  = Preset::compatible_printers_condition(config); | ||||
|     std::string &inherits                       = Preset::inherits(config); | ||||
|     compatible_printers_condition_values.resize(num_extruders + 2, std::string()); | ||||
|     inherits_values.resize(num_extruders + 2, std::string()); | ||||
| 
 | ||||
|     // 1) Create a name from the file name.
 | ||||
|     // Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles.
 | ||||
|     std::string name = is_external ? boost::filesystem::path(name_or_path).filename().string() : name_or_path; | ||||
|  | @ -504,24 +561,31 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool | |||
|     // First load the print and printer presets.
 | ||||
|     for (size_t i_group = 0; i_group < 2; ++ i_group) { | ||||
|         PresetCollection &presets = (i_group == 0) ? this->prints : this->printers; | ||||
| 		Preset &preset = presets.load_preset(is_external ? name_or_path : presets.path_from_name(name), name, config); | ||||
|         if (is_external) | ||||
|             preset.is_external = true; | ||||
|         // Split the "compatible_printers_condition" and "inherits" values one by one from a single vector to the print & printer profiles.
 | ||||
|         size_t idx = (i_group == 0) ? 0 : num_extruders + 1; | ||||
|         inherits                      = inherits_values[idx]; | ||||
|         compatible_printers_condition = compatible_printers_condition_values[idx]; | ||||
| 		if (is_external) | ||||
|             presets.load_external_preset(name_or_path, name, | ||||
|                 config.opt_string((i_group == 0) ? "print_settings_id" : "printer_settings_id", true),  | ||||
|                 config); | ||||
|         else | ||||
|             preset.save(); | ||||
|             presets.load_preset(presets.path_from_name(name), name, config).save(); | ||||
|     } | ||||
| 
 | ||||
|     // 3) Now load the filaments. If there are multiple filament presets, split them and load them.
 | ||||
|     auto   *nozzle_diameter   = dynamic_cast<const ConfigOptionFloats*>(config.option("nozzle_diameter")); | ||||
|     auto   *filament_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("filament_diameter")); | ||||
|     size_t  num_extruders     = std::min(nozzle_diameter->values.size(), filament_diameter->values.size()); | ||||
|     auto old_filament_profile_names = config.option<ConfigOptionStrings>("filament_settings_id", true); | ||||
| 	old_filament_profile_names->values.resize(num_extruders, std::string()); | ||||
|     config.option<ConfigOptionStrings>("default_filament_profile", true)->values.resize(num_extruders, std::string()); | ||||
| 
 | ||||
|     if (num_extruders <= 1) { | ||||
|         Preset &preset = this->filaments.load_preset( | ||||
| 			is_external ? name_or_path : this->filaments.path_from_name(name), name, config); | ||||
|         // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
 | ||||
|         inherits                      = inherits_values[1]; | ||||
|         compatible_printers_condition = compatible_printers_condition_values[1]; | ||||
|         if (is_external) | ||||
|             preset.is_external = true; | ||||
|             this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config); | ||||
|         else | ||||
|             preset.save(); | ||||
|             this->filaments.load_preset(this->filaments.path_from_name(name), name, config).save(); | ||||
|         this->filament_presets.clear(); | ||||
|         this->filament_presets.emplace_back(name); | ||||
|     } else { | ||||
|  | @ -543,21 +607,30 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool | |||
|         // Load the configs into this->filaments and make them active.
 | ||||
|         this->filament_presets.clear(); | ||||
|         for (size_t i = 0; i < configs.size(); ++ i) { | ||||
|             char suffix[64]; | ||||
|             if (i == 0) | ||||
|                 suffix[0] = 0; | ||||
|             else | ||||
|                 sprintf(suffix, " (%d)", i); | ||||
|             std::string new_name = name + suffix; | ||||
|             DynamicPrintConfig &cfg = configs[i]; | ||||
|             // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
 | ||||
|             cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1]; | ||||
|             cfg.opt_string("inherits", true)                      = inherits_values[i + 1]; | ||||
|             // Load all filament presets, but only select the first one in the preset dialog.
 | ||||
|             Preset &preset = this->filaments.load_preset( | ||||
| 				is_external ? name_or_path : this->filaments.path_from_name(new_name), | ||||
|                 new_name, std::move(configs[i]), i == 0); | ||||
|             Preset *loaded = nullptr; | ||||
|             if (is_external) | ||||
|                 preset.is_external = true; | ||||
|             else | ||||
|                 preset.save(); | ||||
|             this->filament_presets.emplace_back(new_name); | ||||
|                 loaded = &this->filaments.load_external_preset(name_or_path, name, | ||||
|                     (i < old_filament_profile_names->values.size()) ? old_filament_profile_names->values[i] : "", | ||||
|                     std::move(cfg), i == 0); | ||||
|             else { | ||||
|                 // Used by the config wizard when creating a custom setup.
 | ||||
|                 // Therefore this block should only be called for a single extruder.
 | ||||
|                 char suffix[64]; | ||||
|                 if (i == 0) | ||||
|                     suffix[0] = 0; | ||||
|                 else | ||||
|                     sprintf(suffix, "%d", i); | ||||
|                 std::string new_name = name + suffix; | ||||
|                 loaded = &this->filaments.load_preset(this->filaments.path_from_name(new_name), | ||||
|                     new_name, std::move(cfg), i == 0); | ||||
|                 loaded->save(); | ||||
|             } | ||||
|             this->filament_presets.emplace_back(loaded->name); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -175,7 +175,7 @@ protected: | |||
| 	std::vector<std::string>	m_reload_dependent_tabs = {}; | ||||
| 	enum OptStatus { osSystemValue = 1, osInitValue = 2 }; | ||||
| 	std::map<std::string, int>	m_options_list; | ||||
| 	int							m_opt_status_value; | ||||
| 	int							m_opt_status_value = 0; | ||||
| 
 | ||||
| 	t_icon_descriptions	m_icon_descriptions = {}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -74,13 +74,13 @@ | |||
|     static StaticPrintConfig* new_GCodeConfig() | ||||
|         %code{% RETVAL = new GCodeConfig(); %}; | ||||
|     static StaticPrintConfig* new_PrintConfig() | ||||
|         %code{% RETVAL = new PrintConfig(); %}; | ||||
|         %code{% RETVAL = static_cast<GCodeConfig*>(new PrintConfig()); %}; | ||||
|     static StaticPrintConfig* new_PrintObjectConfig() | ||||
|         %code{% RETVAL = new PrintObjectConfig(); %}; | ||||
|     static StaticPrintConfig* new_PrintRegionConfig() | ||||
|         %code{% RETVAL = new PrintRegionConfig(); %}; | ||||
|     static StaticPrintConfig* new_FullPrintConfig() | ||||
|         %code{% RETVAL = static_cast<PrintObjectConfig*>(new FullPrintConfig()); %}; | ||||
|         %code{% RETVAL = static_cast<GCodeConfig*>(new FullPrintConfig()); %}; | ||||
|     ~StaticPrintConfig(); | ||||
|     bool has(t_config_option_key opt_key); | ||||
|     SV* as_hash() | ||||
|  | @ -119,7 +119,7 @@ | |||
|             auto config = new FullPrintConfig(); | ||||
|             try { | ||||
|                 config->load(path); | ||||
|                 RETVAL = static_cast<PrintObjectConfig*>(config); | ||||
|                 RETVAL = static_cast<GCodeConfig*>(config); | ||||
|             } catch (std::exception& e) { | ||||
|                 delete config; | ||||
|                 croak("Error extracting configuration from %s:\n%s\n", path, e.what()); | ||||
|  |  | |||
|  | @ -133,7 +133,7 @@ _constant() | |||
|     ~Print(); | ||||
| 
 | ||||
|     Ref<StaticPrintConfig> config() | ||||
|         %code%{ RETVAL = &THIS->config; %}; | ||||
|         %code%{ RETVAL = static_cast<GCodeConfig*>(&THIS->config); %}; | ||||
|     Ref<StaticPrintConfig> default_object_config() | ||||
|         %code%{ RETVAL = &THIS->default_object_config; %}; | ||||
|     Ref<StaticPrintConfig> default_region_config() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv