Merge remote-tracking branch 'upstream/main' into haryr/aug25-rebase

# Conflicts:
#	src/libslic3r/GCode/ToolOrdering.cpp
#	src/libslic3r/Print.cpp
#	src/libslic3r/PrintApply.cpp
#	src/libslic3r/PrintConfig.cpp
#	src/slic3r/GUI/Tab.cpp
This commit is contained in:
harrierpigeon
2026-08-30 23:30:51 -05:00
110 changed files with 38067 additions and 306 deletions
+57 -12
View File
@@ -577,22 +577,67 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
}
// BBS
static const char* keys[] = { "support_filament", "support_interface_filament"};
for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
std::string key = std::string(keys[i]);
// Reset filament overrides pointing at a slot that no longer exists. Support and the wipe
// tower additionally reject mixed slots: the engine consumes those keys directly, so a virtual
// slot would reach the G-code unresolved, while the per-feature keys are resolved per layer.
static const char* physical_only_keys[] = { "support_filament", "support_interface_filament", "wipe_tower_filament" };
static const char* feature_keys[] = { "outer_wall_filament_id", "inner_wall_filament_id",
"sparse_infill_filament_id", "internal_solid_filament_id",
"top_surface_filament_id", "bottom_surface_filament_id" };
auto reset_invalid_filament = [this, config, filament_cnt](const char* key, bool allow_mixed) {
auto* opt = dynamic_cast<ConfigOptionInt*>(config->option(key, false));
if (opt != nullptr) {
if (opt->getInt() > filament_cnt) {
DynamicPrintConfig new_conf = *config;
const DynamicPrintConfig *conf_temp = wxGetApp().plater()->config();
int new_value = 0;
if (conf_temp != nullptr && conf_temp->has(key)) {
new_value = conf_temp->opt_int(key);
if (opt == nullptr)
return;
const int val = opt->getInt();
const bool out_of_range = val > filament_cnt;
const bool is_mixed = !allow_mixed && val > 0 && val <= filament_cnt &&
wxGetApp().preset_bundle->is_mixed_filament(val - 1);
if (!out_of_range && !is_mixed)
return;
DynamicPrintConfig new_conf = *config;
int new_value = 0;
if (out_of_range) {
const DynamicPrintConfig *conf_temp = wxGetApp().plater()->config();
if (conf_temp != nullptr && conf_temp->has(key))
new_value = conf_temp->opt_int(key);
}
new_conf.set_key_value(key, new ConfigOptionInt(new_value));
apply(config, &new_conf);
};
for (const char* key : physical_only_keys)
reset_invalid_filament(key, false);
for (const char* key : feature_keys)
reset_invalid_filament(key, true);
// Sub-layer splitting divides each layer by the mix ratio; an adaptive layer profile makes
// those sub-layer heights vary per layer, which degrades the blend. Warn once per enable.
{
static bool s_mixed_sublayer_warned = false;
bool sublayer_on = config->opt_bool("enable_mixed_color_sublayer");
if (sublayer_on && !s_mixed_sublayer_warned &&
wxGetApp().app_config->get("no_warn_mixed_sublayer_variable_layer") != "1") {
bool has_variable_layer = false;
for (const auto* obj : wxGetApp().model().objects) {
if (obj->layer_height_profile.get().size() > 4) {
has_variable_layer = true;
break;
}
new_conf.set_key_value(key, new ConfigOptionInt(new_value));
apply(config, &new_conf);
}
if (has_variable_layer) {
MessageDialog dialog(m_msg_dlg_parent,
_L("Using variable layer height together with mixed color sublayer may result in poor color mixing quality."),
"", wxICON_WARNING | wxOK);
dialog.show_dsa_button();
is_msg_dlg_already_exist = true;
dialog.ShowModal();
is_msg_dlg_already_exist = false;
if (dialog.get_checkbox_state())
wxGetApp().app_config->set("no_warn_mixed_sublayer_variable_layer", "1");
s_mixed_sublayer_warned = true;
}
}
if (!sublayer_on)
s_mixed_sublayer_warned = false;
}
if (config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None &&