Compare commits

...
Author SHA1 Message Date
Hanif Koh 8535c40466 Keep User Preset Values on Extruder Variants They Don't List
A user preset stores the variant list its parent had when it was saved.
When the parent later gains variants, update_diff_values_to_child_config
matched variants by name only and left the new ones at the parent's
value, so the user's settings were silently replaced there, and a
re-save wrote the system values into the user's file.

An unmatched parent variant now takes the child's first variant of the
same extruder, the rule slicing already uses in get_config_index_base.
A child without a variant list covers the parent's first extruder. The
name match also no longer indexes the child's extruder ids when it has
none.
2026-10-01 22:12:18 +08:00
2 changed files with 98 additions and 2 deletions
+23 -2
View File
@@ -11582,8 +11582,20 @@ void DynamicPrintConfig::update_diff_values_to_child_config(DynamicPrintConfig&
else
variant_index.resize(1, 0);
// A parent variant the child does not list (the parent gained it after the child was saved, or the
// child lists none) takes the child's first variant of the same extruder, as slicing does in
// get_config_index_base. Left unmatched, the parent's value would silently replace the user's.
auto same_extruder = [&](int i, int child_extruder_id) {
return cur_extruder_ids.empty() || child_extruder_id < 0 ||
(i < int(cur_extruder_ids.size()) && cur_extruder_ids[i] == child_extruder_id);
};
if (target_variant_count == 0) {
variant_index[0] = 0;
// The child's one value belongs to the extruder of the parent's first variant.
const int child_extruder_id = cur_extruder_ids.empty() ? -1 : cur_extruder_ids[0];
for (int i = 0; i < int(variant_index.size()); i++)
if (i == 0 || same_extruder(i, child_extruder_id))
variant_index[i] = 0;
}
else if ((cur_extruder_ids.size() > 0) && cur_variant_count != cur_extruder_ids.size()){
//should not happen
@@ -11601,13 +11613,22 @@ void DynamicPrintConfig::update_diff_values_to_child_config(DynamicPrintConfig&
for (int j = 0; j < target_variant_count; j++)
{
if ((cur_extruder_variants[i] == target_extruder_variants[j])
&&(cur_extruder_ids.empty() || (cur_extruder_ids[i] == target_extruder_ids[j])))
&&(cur_extruder_ids.empty() || target_extruder_ids.empty() || (cur_extruder_ids[i] == target_extruder_ids[j])))
{
variant_index[i] = j;
break;
}
}
}
for (int i = 0; i < cur_variant_count; i++) {
if (variant_index[i] != -1)
continue;
for (int j = 0; j < target_variant_count; j++)
if (same_extruder(i, target_extruder_ids.empty() ? -1 : target_extruder_ids[j])) {
variant_index[i] = j;
break;
}
}
}
const t_config_option_keys &keys = new_config.keys();
+75
View File
@@ -421,6 +421,81 @@ SCENARIO("update_diff_values_to_child_config tolerates legacy machine-limit vect
}
}
SCENARIO("update_diff_values_to_child_config keeps a child's values on variants it does not list",
"[Config][Variant]") {
std::set<std::string> no_keys;
auto variants = [](std::initializer_list<std::string> names) { return new Slic3r::ConfigOptionStrings(names); };
GIVEN("A filament parent with three variants") {
Slic3r::DynamicPrintConfig parent;
parent.set_key_value("filament_extruder_variant",
variants({"Direct Drive Standard", "Bowden Standard", "Direct Drive High Flow"}));
parent.set_deserialize_strict("nozzle_temperature", "220,220,220");
WHEN("the child was saved when the parent had only its first variant") {
Slic3r::DynamicPrintConfig child;
child.set_key_value("filament_extruder_variant", variants({"Direct Drive Standard"}));
child.set_deserialize_strict("nozzle_temperature", "199");
parent.update_diff_values_to_child_config(child, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the child's value applies to every variant") {
REQUIRE(parent.opt_serialize("nozzle_temperature") == "199,199,199");
}
}
WHEN("the child lists every variant, in another order") {
Slic3r::DynamicPrintConfig child;
child.set_key_value("filament_extruder_variant",
variants({"Bowden Standard", "Direct Drive High Flow", "Direct Drive Standard"}));
child.set_deserialize_strict("nozzle_temperature", "190,205,199");
parent.update_diff_values_to_child_config(child, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("each variant keeps its own value") {
REQUIRE(parent.opt_serialize("nozzle_temperature") == "199,190,205");
}
}
WHEN("the child lists no variants") {
Slic3r::DynamicPrintConfig child;
child.set_deserialize_strict("nozzle_temperature", "199");
parent.update_diff_values_to_child_config(child, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the child's value applies to every variant") {
REQUIRE(parent.opt_serialize("nozzle_temperature") == "199,199,199");
}
}
}
GIVEN("A two-extruder printer parent with two variants per extruder") {
Slic3r::DynamicPrintConfig parent;
parent.set_key_value("printer_extruder_variant",
variants({"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"}));
parent.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 1, 2, 2}));
parent.set_deserialize_strict("retraction_length", "0.8,0.8,0.8,0.8");
WHEN("the child lists only the Standard variant of each extruder") {
Slic3r::DynamicPrintConfig child;
child.set_key_value("printer_extruder_variant", variants({"Direct Drive Standard", "Direct Drive Standard"}));
child.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2}));
child.set_deserialize_strict("retraction_length", "1.1,2.2");
parent.update_diff_values_to_child_config(child, "printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("each extruder's High Flow variant takes that extruder's value") {
REQUIRE(parent.opt_serialize("retraction_length") == "1.1,1.1,2.2,2.2");
}
}
WHEN("the child lists no variants") {
Slic3r::DynamicPrintConfig child;
child.set_deserialize_strict("retraction_length", "1.1");
parent.update_diff_values_to_child_config(child, "printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("only the first extruder's variants take the child's value") {
REQUIRE(parent.opt_serialize("retraction_length") == "1.1,1.1,0.8,0.8");
}
}
}
}
// SCENARIO("DynamicPrintConfig JSON serialization", "[Config]") {
// WHEN("DynamicPrintConfig is serialized and deserialized") {
// auto now = std::chrono::high_resolution_clock::now();