diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index bd6fb3d457..ad80156e01 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -230,37 +230,64 @@ double Flow::mm3_per_mm() const return res; } +static float min_nozzle_diameter(const PrintObject &print_object) +{ + const ConfigOptionFloats &nozzle_diameters = print_object.print()->config().nozzle_diameter; + float min_nozzle_diameter = std::numeric_limits::max(); + + for (const double nozzle_diameter : nozzle_diameters.values) { + min_nozzle_diameter = std::min(min_nozzle_diameter, static_cast(nozzle_diameter)); + } + + return min_nozzle_diameter; +} + Flow support_material_flow(const PrintObject *object, float layer_height) { + const PrintConfig &print_config = object->print()->config(); + const int extruder = object->config().support_material_extruder - 1; + + // If object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter. + const float nozzle_diameter = extruder >= 0 ? static_cast(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object); + return Flow::new_from_config_width( frSupportMaterial, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. (object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width, - // if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. - float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)), + nozzle_diameter, (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value)); } Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height) { const PrintConfig &print_config = object->print()->config(); - const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width; + const int extruder = object->config().support_material_extruder - 1; + + // If object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter. + const float nozzle_diameter = extruder >= 0 ? static_cast(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object); + const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width; + return Flow::new_from_config_width( frSupportMaterial, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. (width.value > 0) ? width : object->config().extrusion_width, - float(print_config.nozzle_diameter.get_at(object->config().support_material_extruder-1)), + nozzle_diameter, (layer_height > 0.f) ? layer_height : float(print_config.first_layer_height.get_abs_value(object->config().layer_height.value))); } Flow support_material_interface_flow(const PrintObject *object, float layer_height) { + const PrintConfig &print_config = object->print()->config(); + const int extruder = object->config().support_material_interface_extruder - 1; + + // If object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter. + const float nozzle_diameter = extruder >= 0 ? static_cast(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object); + return Flow::new_from_config_width( frSupportMaterialInterface, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. (object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width, - // if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. - float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)), + nozzle_diameter, (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value)); } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index e18bd7b951..090ea06741 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -510,6 +510,7 @@ static std::vector s_Preset_print_options { "perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "wall_distribution_count", "min_feature_size", "min_bead_width", "top_one_perimeter_type", "only_one_perimeter_first_layer", + "automatic_extrusion_widths", "automatic_infill_combination", "automatic_infill_combination_max_layer_height", }; static std::vector s_Preset_filament_options { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f7f15cd49c..7097576f20 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -283,6 +283,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n steps.emplace_back(psSkirtBrim); } else if (opt_key == "avoid_crossing_curled_overhangs") { osteps.emplace_back(posEstimateCurledExtrusions); + } else if (opt_key == "automatic_extrusion_widths") { + osteps.emplace_back(posPerimeters); } else { // for legacy, if we can't handle this option let's invalidate all steps //FIXME invalidate all steps of all objects as well? @@ -627,15 +629,19 @@ std::string Print::validate(std::vector* warnings) const if (this->has_wipe_tower() && ! m_objects.empty()) { // Make sure all extruders use same diameter filament and have the same nozzle diameter // EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments - double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front()); + double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front()); double first_filament_diam = m_config.filament_diameter.get_at(extruders.front()); + + bool allow_nozzle_diameter_differ_warning = (warnings != nullptr); for (const auto& extruder_idx : extruders) { - double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx); + double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx); double filament_diam = m_config.filament_diameter.get_at(extruder_idx); - if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam - || std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) - return _u8L("The wipe tower is only supported if all extruders have the same nozzle diameter " - "and use filaments of the same diameter."); + if (allow_nozzle_diameter_differ_warning && (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam)) { + allow_nozzle_diameter_differ_warning = false; + warnings->emplace_back("_WIPE_TOWER_NOZZLE_DIAMETER_DIFFER"); + } else if (std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1) { + return _u8L("The wipe tower is only supported if all extruders use filaments of the same diameter."); + } } if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && @@ -738,13 +744,11 @@ std::string Print::validate(std::vector* warnings) const }; for (PrintObject *object : m_objects) { if (object->has_support_material()) { - if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) { + if (warnings != nullptr && (object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) { // The object has some form of support and either support_material_extruder or support_material_interface_extruder - // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles - // are of the same diameter. - return _u8L("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."); + // will be printed with the current tool without a forced tool change. + // Notify the user that printing supports with different nozzle diameters is experimental and requires caution. + warnings->emplace_back("_SUPPORT_NOZZLE_DIAMETER_DIFFER"); } if (this->has_wipe_tower() && object->config().support_material_style != smsOrganic) { if (object->config().support_material_contact_distance == 0) { diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1d6aef73ce..85841e87e7 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -527,6 +527,31 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(ArcFittingType::Disabled)); + def = this->add("automatic_extrusion_widths", coBool); + def->label = L("Automatic extrusion widths calculation"); + def->category = L("Extrusion Width"); + def->tooltip = L("Automatically calculates extrusion widths based on the nozzle diameter of the currently used extruder. " + "This setting is essential for printing with different nozzle diameters."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("automatic_infill_combination", coBool); + def->label = L("Automatic infill combination"); + def->category = L("Infill"); + def->tooltip = L("This feature automatically combine infill of several layers and speeds up your print by extruding thicker " + "infill layers while preserving thin perimeters, thus accuracy."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("automatic_infill_combination_max_layer_height", coFloatOrPercent); + def->label = L("Automatic infill combination - Max layer height"); + def->category = L("Infill"); + def->tooltip = L("Maximum layer height for combining infill when automatic infill combining is enabled. " + "Maximum layer height could be specified either as an absolute in millimeters value or as a percentage of nozzle diameter. " + "For printing with different nozzle diameters, it is recommended to use percentage value over absolute value."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloatOrPercent(100., true)); + // Maximum extruder temperature, bumped to 1500 to support printing of glass. const int max_temp = 1500; def = this->add("avoid_crossing_curled_overhangs", coBool); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 93bb6747be..dac7561bdd 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -685,6 +685,8 @@ PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE( PrintRegionConfig, + ((ConfigOptionBool, automatic_infill_combination)) + ((ConfigOptionFloatOrPercent, automatic_infill_combination_max_layer_height)) ((ConfigOptionFloat, bridge_angle)) ((ConfigOptionInt, bottom_solid_layers)) ((ConfigOptionFloat, bottom_solid_min_thickness)) @@ -898,6 +900,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( PrintConfig, (MachineEnvelopeConfig, GCodeConfig), + ((ConfigOptionBool, automatic_extrusion_widths)) ((ConfigOptionBool, avoid_crossing_curled_overhangs)) ((ConfigOptionBool, avoid_crossing_perimeters)) ((ConfigOptionFloatOrPercent, avoid_crossing_perimeters_max_detour)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index bd0542ca6a..f9c5727b44 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -808,6 +808,8 @@ bool PrintObject::invalidate_state_by_config_options( opt_key == "interface_shells" || opt_key == "infill_only_where_needed" || opt_key == "infill_every_layers" + || opt_key == "automatic_infill_combination" + || opt_key == "automatic_infill_combination_max_layer_height" || opt_key == "solid_infill_every_layers" || opt_key == "ensure_vertical_shell_thickness" || opt_key == "bottom_solid_min_thickness" @@ -3053,16 +3055,24 @@ void PrintObject::discover_horizontal_shells() void PrintObject::combine_infill() { // Work on each region separately. - for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { - const PrintRegion ®ion = this->printing_region(region_id); - const size_t every = region.config().infill_every_layers.value; - if (every < 2 || region.config().fill_density == 0.) + for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) { + const PrintRegion ®ion = this->printing_region(region_id); + const size_t combine_infill_every_n_layers = region.config().infill_every_layers.value; + const bool automatic_infill_combination = region.config().automatic_infill_combination; + const bool enable_combine_infill = automatic_infill_combination || combine_infill_every_n_layers >= 2; + + if (!enable_combine_infill || region.config().fill_density == 0.) { continue; + } + // Limit the number of combined layers to the maximum height allowed by this regions' nozzle. //FIXME limit the layer height to max_layer_height - double nozzle_diameter = std::min( - this->print()->config().nozzle_diameter.get_at(region.config().infill_extruder.value - 1), - this->print()->config().nozzle_diameter.get_at(region.config().solid_infill_extruder.value - 1)); + const double nozzle_diameter = std::min(this->print()->config().nozzle_diameter.get_at(region.config().infill_extruder.value - 1), + this->print()->config().nozzle_diameter.get_at(region.config().solid_infill_extruder.value - 1)); + + const double automatic_infill_combination_max_layer_height = region.config().automatic_infill_combination_max_layer_height.get_abs_value(nozzle_diameter); + const double max_combine_layer_height = automatic_infill_combination ? std::min(automatic_infill_combination_max_layer_height, nozzle_diameter) : nozzle_diameter; + // define the combinations std::vector combine(m_layers.size(), 0); { @@ -3070,19 +3080,21 @@ void PrintObject::combine_infill() size_t num_layers = 0; for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) { m_print->throw_if_canceled(); - const Layer *layer = m_layers[layer_idx]; - if (layer->id() == 0) + const Layer &layer = *m_layers[layer_idx]; + if (layer.id() == 0) // Skip first print layer (which may not be first layer in array because of raft). continue; + // Check whether the combination of this layer with the lower layers' buffer // would exceed max layer height or max combined layer count. - if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= every) { + if (current_height + layer.height >= max_combine_layer_height + EPSILON || (!automatic_infill_combination && num_layers >= combine_infill_every_n_layers)) { // Append combination to lower layer. combine[layer_idx - 1] = num_layers; current_height = 0.; num_layers = 0; } - current_height += layer->height; + + current_height += layer.height; ++ num_layers; } diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index dca9d2e58e..ac6b29a2d5 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -38,6 +38,64 @@ void ConfigManipulation::toggle_field(const std::string& opt_key, const bool tog cb_toggle_field(opt_key, toggle, opt_index); } +std::optional handle_automatic_extrusion_widths(const DynamicPrintConfig &config, const bool is_global_config, wxWindow *msg_dlg_parent) +{ + const std::vector extrusion_width_parameters = {"extrusion_width", "external_perimeter_extrusion_width", "first_layer_extrusion_width", + "infill_extrusion_width", "perimeter_extrusion_width", "solid_infill_extrusion_width", + "support_material_extrusion_width", "top_infill_extrusion_width"}; + + auto is_zero_width = [](const ConfigOptionFloatOrPercent &opt) -> bool { + return opt.value == 0. && !opt.percent; + }; + + auto is_parameters_adjustment_needed = [&is_zero_width, &config, &extrusion_width_parameters]() -> bool { + if (!config.opt_bool("automatic_extrusion_widths")) { + return false; + } + + for (const std::string &extrusion_width_parameter : extrusion_width_parameters) { + if (!is_zero_width(*config.option(extrusion_width_parameter))) { + return true; + } + } + + return false; + }; + + if (is_parameters_adjustment_needed()) { + wxString msg_text = _(L("The automatic extrusion widths calculation requires:\n" + "- Default extrusion width: 0\n" + "- First layer extrusion width: 0\n" + "- Perimeter extrusion width: 0\n" + "- External perimeter extrusion width: 0\n" + "- Infill extrusion width: 0\n" + "- Solid infill extrusion width: 0\n" + "- Top infill extrusion width: 0\n" + "- Support material extrusion width: 0")); + + if (is_global_config) { + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable automatic extrusion widths calculation?")); + } + + MessageDialog dialog(msg_dlg_parent, msg_text, _(L("Automatic extrusion widths calculation")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + + const int answer = dialog.ShowModal(); + DynamicPrintConfig new_conf = config; + if (!is_global_config || answer == wxID_YES) { + for (const std::string &extrusion_width_parameter : extrusion_width_parameters) { + new_conf.set_key_value(extrusion_width_parameter, new ConfigOptionFloatOrPercent(0., false)); + } + } else { + new_conf.set_key_value("automatic_extrusion_widths", new ConfigOptionBool(false)); + } + + return new_conf; + } + + return std::nullopt; +} + void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) { // #ys_FIXME_to_delete @@ -76,7 +134,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con double fill_density = config->option("fill_density")->value; if (config->opt_bool("spiral_vase") && - ! (config->opt_int("perimeters") == 1 && + ! (config->opt_int("perimeters") == 1 && config->opt_int("top_solid_layers") == 0 && fill_density == 0 && ! config->opt_bool("support_material") && @@ -102,7 +160,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); new_conf.set_key_value("support_material", new ConfigOptionBool(false)); new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); - new_conf.set_key_value("thin_walls", new ConfigOptionBool(false)); + new_conf.set_key_value("thin_walls", new ConfigOptionBool(false)); fill_density = 0; support = false; } @@ -213,6 +271,13 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } } } + + if (config->opt_bool("automatic_extrusion_widths")) { + std::optional new_config = handle_automatic_extrusion_widths(*config, is_global_config, m_msg_dlg_parent); + if (new_config.has_value()) { + apply(config, &(*new_config)); + } + } } void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) @@ -227,11 +292,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("overhang_speed_" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds")); } - bool have_infill = config->option("fill_density")->value > 0; + const bool have_infill = config->option("fill_density")->value > 0; + const bool has_automatic_infill_combination = config->option("automatic_infill_combination")->value; // infill_extruder uses the same logic as in Print::extruders() - for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", - "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder", "infill_anchor_max" }) + for (auto el : { "fill_pattern","solid_infill_every_layers", "solid_infill_below_area", "infill_extruder", + "infill_anchor_max", "automatic_infill_combination" }) { toggle_field(el, have_infill); + } + + toggle_field("infill_every_layers", have_infill && !has_automatic_infill_combination); + toggle_field("automatic_infill_combination_max_layer_height", have_infill && has_automatic_infill_combination); + // Only allow configuration of open anchors if the anchoring is enabled. bool has_infill_anchors = have_infill && config->option("infill_anchor_max")->value > 0; toggle_field("infill_anchor", has_infill_anchors); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 99021fa8ab..9674b2f471 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -133,7 +133,7 @@ void NotificationManager::NotificationIDProvider::release_id(int) {} #endif //------PopNotification-------- -NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) : +NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler, const bool multiline) : m_data (n) , m_id_provider (id_provider) , m_text1 (n.text1) @@ -141,6 +141,7 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, , m_text2 (n.text2) , m_evt_handler (evt_handler) , m_notification_start (GLCanvas3D::timestamp_now()) + , m_multiline (multiline) {} void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) @@ -2157,10 +2158,11 @@ void NotificationManager::push_notification(NotificationType type, const std::string& hypertext, std::function callback, const std::string& text_after, - int timestamp) + const int timestamp, + const bool multiline) { int duration = get_standard_duration(level); - push_notification_data({ type, level, duration, text, hypertext, callback, text_after }, timestamp); + push_notification_data({ type, level, duration, text, hypertext, callback, text_after }, timestamp, multiline); } void NotificationManager::push_delayed_notification(const NotificationType type, std::function condition_callback, int64_t initial_delay, int64_t delay_interval) @@ -2839,9 +2841,9 @@ void NotificationManager::push_updated_item_info_notification(InfoItemType type) } } -bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp) +bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp, const bool multiline) { - return push_notification_data(std::make_unique(notification_data, m_id_provider, m_evt_handler), timestamp); + return push_notification_data(std::make_unique(notification_data, m_id_provider, m_evt_handler, multiline), timestamp); } bool NotificationManager::push_notification_data(std::unique_ptr notification, int timestamp) { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 0c6390f2ec..57ecbf4719 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -140,6 +140,10 @@ enum class NotificationType BedTemperaturesDiffer, // Notification that shrinkage compensations for the used filaments differ. ShrinkageCompensationsDiffer, + // Notification about using wipe tower with different nozzle diameters. + WipeTowerNozzleDiameterDiffer, + // Notification about using supports with different nozzle diameters. + SupportNozzleDiameterDiffer, }; class NotificationManager @@ -179,7 +183,7 @@ public: // Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotificationLevel. // ErrorNotificationLevel are never faded out. void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "", - std::function callback = std::function(), const std::string& text_after = "", int timestamp = 0); + std::function callback = std::function(), const std::string& text_after = "", int timestamp = 0, bool multiline = false); // Pushes basic_notification with delay. See push_delayed_notification_data. void push_delayed_notification(const NotificationType type, std::function condition_callback, int64_t initial_delay, int64_t delay_interval); // Removes all notifications of type from m_waiting_notifications @@ -342,7 +346,7 @@ private: Paused }; - PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); + PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler, bool multiline = false); virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width); // close will dissapear notification on next render @@ -853,7 +857,7 @@ private: //pushes notification into the queue of notifications that are rendered //can be used to create custom notification - bool push_notification_data(const NotificationData& notification_data, int timestamp); + bool push_notification_data(const NotificationData& notification_data, int timestamp, bool multiline = false); bool push_notification_data(std::unique_ptr notification, int timestamp); // Delayed notifications goes first to the m_waiting_notifications vector and only after remaining time is <= 0 // and condition callback is success, notification is regular pushed from update function. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 83a16e1f32..adf299b97d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2098,12 +2098,16 @@ void Plater::priv::process_validation_warning(const std::vector& wa if (warnings.empty()) notification_manager->close_notification_of_type(NotificationType::ValidateWarning); - // Always close warnings BedTemperaturesDiffer and ShrinkageCompensationsDiffer before next processing. + // Always close warnings BedTemperaturesDiffer, ShrinkageCompensationsDiffer, WipeTowerNozzleDiameterDiffer and SupportNozzleDiameterDiffer before next processing. notification_manager->close_notification_of_type(NotificationType::BedTemperaturesDiffer); notification_manager->close_notification_of_type(NotificationType::ShrinkageCompensationsDiffer); + notification_manager->close_notification_of_type(NotificationType::WipeTowerNozzleDiameterDiffer); + notification_manager->close_notification_of_type(NotificationType::SupportNozzleDiameterDiffer); for (std::string text : warnings) { std::string hypertext = ""; + std::string text_after = ""; + bool multiline = false; NotificationType notification_type = NotificationType::ValidateWarning; std::function action_fn = [](wxEvtHandler*){ return false; }; @@ -2128,12 +2132,26 @@ void Plater::priv::process_validation_warning(const std::vector& wa text = _u8L("Filament shrinkage will not be used because filament shrinkage " "for the used filaments differs significantly."); notification_type = NotificationType::ShrinkageCompensationsDiffer; + } else if (text == "_WIPE_TOWER_NOZZLE_DIAMETER_DIFFER") { + text = _u8L("Using the wipe tower for extruders with different nozzle diameters " + "is experimental, so proceed with caution."); + notification_type = NotificationType::WipeTowerNozzleDiameterDiffer; + } else if (text == "_SUPPORT_NOZZLE_DIAMETER_DIFFER") { + text = _u8L("Printing supports with different nozzle diameters " + "is experimental. For best results, switch to Organic supports and"); + hypertext = _u8L("assign a specific extruder for supports."); + multiline = true; + notification_type = NotificationType::SupportNozzleDiameterDiffer; + action_fn = [](wxEvtHandler*) { + GUI::wxGetApp().jump_to_option("support_material_extruder", Preset::Type::TYPE_PRINT, boost::nowide::widen("Multiple Extruders")); + return false; + }; } notification_manager->push_notification( notification_type, NotificationManager::NotificationLevel::WarningNotificationLevel, - _u8L("WARNING:") + "\n" + text, hypertext, action_fn + _u8L("WARNING:") + "\n" + text, hypertext, action_fn, text_after, 0, multiline ); } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 02dfe6cf8b..7b3787b0a5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1503,8 +1503,9 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Reducing printing time")); category_path = "infill_42#"; + optgroup->append_single_option_line("automatic_infill_combination"); + optgroup->append_single_option_line("automatic_infill_combination_max_layer_height"); optgroup->append_single_option_line("infill_every_layers", category_path + "combine-infill-every-x-layers"); - // optgroup->append_single_option_line("infill_only_where_needed", category_path + "only-infill-where-needed"); optgroup = page->new_optgroup(L("Advanced")); optgroup->append_single_option_line("solid_infill_every_layers", category_path + "solid-infill-every-x-layers"); @@ -1662,6 +1663,7 @@ void TabPrint::build() optgroup->append_single_option_line("solid_infill_extrusion_width"); optgroup->append_single_option_line("top_infill_extrusion_width"); optgroup->append_single_option_line("support_material_extrusion_width"); + optgroup->append_single_option_line("automatic_extrusion_widths"); optgroup = page->new_optgroup(L("Overlap")); optgroup->append_single_option_line("infill_overlap");