Merge upstream, and move the IMEX placeholders onto the new def macro

Eleven commits, including a typed-config G-code export speedup, a printer agent
refactor that generalizes the infrastructure beyond Bambu, gyroid optimization,
and three CLI crash fixes.

One conflict, in PrintConfig.cpp. Upstream introduced a new_def macro and began
migrating the placeholder table onto it, adding curr_bed_type that way in the
same block where this branch had added imex_mode, imex_mode_index and
imex_mode_gcode in the older def = this->add(...) form. Both sides are kept and
ours are converted to the macro, which expands to the same three statements and
wraps label and tooltip in L() exactly as before, so nothing changes about what
is registered or what is translatable.

Note for anyone building this branch: the agent refactor adds a dependency,
LibDataChannel, so the deps tree needs dep_DataChannel built before the app will
configure. A distribution package of the same name will be found first if one is
installed, and the resulting error names a missing RelWithDebInfo location
rather than the wrong package, so point LibDataChannel_DIR at the dependency
prefix if that happens.

Verified: 789 targets build clean under -Werror, and the Release suite passes
1665 of 1665, up from 1630 before the merge -- the 35 new cases arrived with it
and all pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-09-30 23:55:21 -04:00
co-authored by Claude Opus 5
344 changed files with 5686 additions and 12023 deletions
+70
View File
@@ -1492,3 +1492,73 @@ TEST_CASE("Static print configs compare, order and hash by their option values",
REQUIRE(c.optptr("gcode_flavor") == &c.gcode_flavor);
}
}
namespace {
// Keys whose values differ between two full configs, compared as text so enum names count too.
std::vector<std::string> differing_keys(const FullPrintConfig &a, const FullPrintConfig &b)
{
std::vector<std::string> keys;
for (const std::string &key : a.keys())
if (a.opt_serialize(key) != b.opt_serialize(key))
keys.push_back(key);
return keys;
}
// Applies source to one full config member by member and to another key by key, as apply() did before
// static configs could apply themselves.
template<class Source> void check_member_apply_matches_key_apply(const Source &source)
{
FullPrintConfig by_member;
FullPrintConfig by_key;
by_member.apply(source);
by_key.apply_only(source, source.keys());
CHECK(differing_keys(by_member, by_key).empty());
CHECK_FALSE(differing_keys(by_member, FullPrintConfig()).empty());
}
} // namespace
TEST_CASE("A static config applies itself onto a config of its type as a lookup by name would", "[Config]")
{
SECTION("region config")
{
PrintRegionConfig region;
region.sparse_infill_pattern.value = ipGyroid;
region.outer_wall_speed.values = {37.};
region.sparse_infill_density.value = 35.;
FullPrintConfig full;
REQUIRE(region.apply_to(full));
check_member_apply_matches_key_apply(region);
}
SECTION("object config")
{
PrintObjectConfig object;
object.seam_position.value = spRear;
object.wall_generator.value = PerimeterGeneratorType::Arachne;
object.support_speed.values = {33.};
object.enable_support.value = true;
FullPrintConfig full;
REQUIRE(object.apply_to(full));
check_member_apply_matches_key_apply(object);
}
SECTION("G-code config, whose enum lists carry their names through a keys map")
{
GCodeConfig gcode;
gcode.z_hop_types.values = {int(zhtSpiral)};
gcode.retraction_length.values = {1.5};
FullPrintConfig full;
REQUIRE(gcode.apply_to(full));
check_member_apply_matches_key_apply(gcode);
}
}
TEST_CASE("A static config applied onto a config of another type falls back to a lookup by name", "[Config]")
{
PrintRegionConfig region;
region.sparse_infill_pattern.value = ipGyroid;
DynamicPrintConfig dynamic;
REQUIRE_FALSE(region.apply_to(dynamic));
dynamic.apply(region);
CHECK(dynamic.opt_serialize("sparse_infill_pattern") == "gyroid");
}